Unity3D NavMeshAgent - c#

I've been attempting to rid myself of this NavMeshAgent error for about 2 weeks now but can't seem to overcome it so I'm turning to SO.
I have a Navigation Mesh, I have prodigally spawned enemies which are placed on the Navigation Mesh however I receive this error constantly to where my console is filled (999+) with this error. The error is:
"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:SetDestination(Vector3)
ZombieAI:Update() (at Assets/Scripts/ZombieAI.cs:137)
Any help on squashing this error would be greatly appreciated as it sucks all performance out of my program to a point of not being usable.
The script is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using FSG.MeshAnimator;
public class ZombieAI : MonoBehaviour
{
/// <summary>
/// Components
/// </summary>
MeshAnimator mesh;
AudioSource audioSrc;
SphereCollider sphereCollider;
CapsuleCollider capsuleCollider;
NavMeshAgent agent;
/// <summary>
/// Child Objects
/// </summary>
GameObject EnemyIcon;
/// <summary>
/// Animations
/// </summary>
public MeshAnimation[] deathAnimations = new MeshAnimation[5];
string curDeathAnimations;
public MeshAnimation[] runAnimations = new MeshAnimation[1];
/// <summary>
/// Sounds
/// </summary>
public AudioSource _as;
public AudioClip[] infectedNoises;
public int randomNoiseNum;
/// <summary>
/// Textures
/// </summary>
public Texture[] mantexture = new Texture[16];
public Texture[] womantexture = new Texture[17];
/// <summary>
/// Health
/// </summary>
public float max_health = 5f;
public float cur_health = 5f;
public float distance;
/// <summary>
/// Awareness
/// </summary>
public bool female;
public bool alive;
public bool spotted = false;
public bool attack = false;
bool create = false;
/// <summary>
/// Targets
/// </summary>
public GameObject target;
/// <summary>
/// Veriables
/// </summary>
public float velocity;
private Vector3 previous;
[Range(0f, 1.35f)]
public float attackRange;
[Range(3f, 5f)]
public float runAttackRange;
[Range(1f, 100f)]
public float detectionRange;
[Range(1f, 10f)]
public float runSpeed = 3.5f;
float onMeshThreshold = 3;
private void Start()
{
if (female == false)
{
gameObject.GetComponent<Renderer>().material.SetTexture("_MainTex", mantexture[Random.Range(0, mantexture.Length)]);
}
if (female == true)
{
GetComponent<Renderer>().material.SetTexture("_MainTex", womantexture[Random.Range(0, womantexture.Length)]);
}
curDeathAnimations = deathAnimations[Random.Range(0, deathAnimations.Length)].name;
//EnemyIcon = transform.Find("Enemy-Icon").gameObject;
mesh = GetComponent<MeshAnimator>();
audioSrc = GetComponent<AudioSource>();
_as = GetComponent<AudioSource>();
sphereCollider = GetComponent<SphereCollider>();
capsuleCollider = GetComponent<CapsuleCollider>();
agent = GetComponent<NavMeshAgent>();
target = GameObject.FindGameObjectWithTag("Player");
alive = true;
if (transform.position.y <= 0 && transform.position.y >= 1)
{
Destroy(gameObject);
}
}
public void Update()
{
if (alive)
{
distance = Vector3.Distance(target.transform.position, transform.position);
velocity = ((transform.position - previous).magnitude) / Time.deltaTime;
previous = transform.position;
if (transform.position.y <= 1 && transform.position.y >= -1)
{
create = true;
if (create == false)
{
Destroy(gameObject);
}
else if (create == true)
{
agent.SetDestination(target.transform.position);
}
}
if (velocity > 0 && !attack)
{
mesh.speed = velocity / 3;
mesh.Play("Run1-0");
}
if (velocity > 0 && attack && spotted)
{
spotted = true;
mesh.Play("Run Attack");
}
else if (velocity == 0 && attack && spotted)
{
mesh.Play("Attack1-0");
}
if (distance < detectionRange)
{
spotted = true;
}
if (spotted && distance < attackRange)
{
Vector3 targetPosition = new Vector3(target.transform.position.x, transform.position.y, target.transform.position.z);
transform.LookAt(targetPosition);
}
randomNoiseNum = Random.Range(0, 400);
if (alive && randomNoiseNum == 20)
{
PlayRandomNoise();
}
}
/* if (alive && distance > attackRange && velocity <= 0.05f && !attack)
{
mesh.Play("Idle1-0");
}*/
if (!alive)
{
//mesh.Play(curDeathAnimations);
//ScoreManager.scoreValue += 1;
Destroy(gameObject, 5);
}
if (cur_health <= 0)
{
mesh.speed = 1;
alive = !alive;
mesh.Play(curDeathAnimations);
//Destroy(mesh,0);
Destroy(EnemyIcon);
Destroy(audioSrc, 0);
Destroy(sphereCollider, 0);
Destroy(capsuleCollider, 0);
Destroy(agent, 0);
alive = false;
}
}
void OnTriggerStay(Collider col)
{
attack = true;
}
void OnTriggerExit(Collider col)
{
attack = false;
}
public void PlayRandomNoise()
{
if (female == true)
{
_as.volume = 2.0f;
_as.clip = infectedNoises[Random.Range(0, infectedNoises.Length)];
_as.pitch = Random.Range(1.10f, 1.35f);
_as.PlayOneShot(_as.clip);
}
else
{
_as.volume = 2.0f;
_as.pitch = Random.Range(0.75f, 1.05f);
_as.clip = infectedNoises[Random.Range(0, infectedNoises.Length)];
_as.PlayOneShot(_as.clip);
}
}
}

Related

How to simulate car moving 2D via WheelJoint2D.motorSpeed?

Please, help me.
The farther from the center of the screen the higher / lower the car speed. Car's RigidBody2D.mass = 1000, wheels's mass = 50. The car object has 2 'WheelJoint2D' components (connected RigidBody = frontwheel and backwheel) and useMotor = true, maximumMotorForce = 10000 (by default).
Here is part of my code (C#):
[RequireComponent(typeof(Rigidbody2D), typeof(WheelJoint2D))]
public class CarBaseMovement : MonoBehaviour, IVehicleMovable
{
public const float GRAVITY = 9.81f;
[Header("Wheels Joint")]
[SerializeField] protected WheelJoint2D _frontWheelJoint;
[SerializeField] protected WheelJoint2D _backWheelJoint;
private int _centerScreenX;
protected Rigidbody2D _rigidBody2D;
private float _movementInput;
private float _deltaMovement;
private float _physicValue;
private JointMotor2D _wheelMotor;
private void Start()
{
// set center screen width
_centerScreenX = Screen.width / 2;
_rigidBody2D = GetComponent<Rigidbody2D>();
if (_rigidBody2D == null || _frontWheelJoint == null || _backWheelJoint == null)
{
throw new ArgumentNullException();
}
_wheelMotor = _backWheelJoint.motor;
}
protected virtual void Update()
{
// _movementInput = Input.GetAxis("Horizontal");
if (Input.GetMouseButton(0))
{
_deltaMovement = Input.mousePosition.x;
GetTouch(_deltaMovement);
SetVelocity();
SetWheelsMotorSpeed();
}
}
/// <summary>
/// Get touch/mouseclick position to determine speed
/// </summary>
/// <param name="touchPos">touch/mouseclick position</param>
protected void GetTouch(float touchPos)
{
if (touchPos > _centerScreenX)
{
_movementInput = touchPos - _centerScreenX;
}
if (touchPos < _centerScreenX)
{
_movementInput = _centerScreenX - touchPos;
}
}
/// <summary>
/// Set velocity
/// </summary>
private void SetVelocity()
{
_physicValue = GRAVITY * Mathf.Sin((transform.eulerAngles.z * Mathf.PI) / 180f) * 80f;
_wheelMotor.motorSpeed = Mathf.Clamp(
_wheelMotor.motorSpeed - ( _movementInput - _physicValue) * Time.deltaTime,
-7000f,
7000f);
}
/// <summary>
/// Set wheels motor speed
/// </summary>
private void SetWheelsMotorSpeed()
{
_frontWheelJoint.motor = _backWheelJoint.motor = _wheelMotor;
}
}

Unity 2D health bar

I am new to coding and Unity
I have the health bar appearing on my screen, but I am not sure how to link the Health script of the health bar to my player script and my player's health script. Simply, I want to make it so when my player gets shot my health bar will lose a heart
my health bar script
using UnityEngine;
using System.Collections;
public class Health : MonoBehaviour {
public int startHealth;
public int healthPerHeart;
private int maxHealth;
private int currentHealth;
public Texture[] heartImages;
public GUITexture heartGUI;
private ArrayList hearts = new ArrayList();
// Spacing:
public float maxHeartsOnRow;
private float spacingX;
private float spacingY;
void Start () {
spacingX = heartGUI.pixelInset.width;
spacingY = -heartGUI.pixelInset.height;
AddHearts(startHealth/healthPerHeart);
}
public void AddHearts(int n) {
for (int i = 0; i <n; i ++) {
Transform newHeart = ((GameObject)Instantiate(heartGUI.gameObject,this.transform.position,Quaternion.identity)).transform; // Creates a new heart
newHeart.parent = transform;
int y = (int)(Mathf.FloorToInt(hearts.Count / maxHeartsOnRow));
int x = (int)(hearts.Count - y * maxHeartsOnRow);
newHeart.GetComponent<GUITexture>().pixelInset = new Rect(x * spacingX,y * spacingY,58,58);
newHeart.GetComponent<GUITexture>().texture = heartImages[0];
hearts.Add(newHeart);
}
maxHealth += n * healthPerHeart;
currentHealth = maxHealth;
UpdateHearts();
}
public void modifyHealth(int amount) {
currentHealth += amount;
currentHealth = Mathf.Clamp(currentHealth,0,maxHealth);
UpdateHearts();
}
void UpdateHearts() {
bool restAreEmpty = false;
int i =0;
foreach (Transform heart in hearts) {
if (restAreEmpty) {
heart.guiTexture.texture = heartImages[0]; // heart is empty
}
else {
i += 1; // current iteration
if (currentHealth >= i * healthPerHeart) {
heart.guiTexture.texture = heartImages[heartImages.Length-1]; // health of current heart is full
}
else {
int currentHeartHealth = (int)(healthPerHeart - (healthPerHeart * i - currentHealth));
int healthPerImage = healthPerHeart / heartImages.Length; // how much health is there per image
int imageIndex = currentHeartHealth / healthPerImage;
if (imageIndex == 0 && currentHeartHealth > 0) {
imageIndex = 1;
}
heart.guiTexture.texture = heartImages[imageIndex];
restAreEmpty = true;
}
}
}
}
}
my player script
/// <summary>
/// Player controller and behavior
/// </summary>
public class PlayerScript : MonoBehaviour
{
public Health health;
/// <summary>
/// 1 - The speed of the ship
/// </summary>
public Vector2 speed = new Vector2(50, 50);
// 2 - Store the movement
private Vector2 movement;
void OnCollisionEnter2D(Collision2D collision)
{
bool damagePlayer = false;
// Collision with enemy
EnemyScript enemy = collision.gameObject.GetComponent<EnemyScript>();
if (enemy != null)
{
// Kill the enemy
HealthScript enemyHealth = enemy.GetComponent<HealthScript>();
if (enemyHealth != null) enemyHealth.Damage(enemyHealth.hp);
damagePlayer = true;
}
// Damage the player
if (damagePlayer)
{
HealthScript playerHealth = this.GetComponent<HealthScript>();
if (playerHealth != null) playerHealth.Damage(1);
}
}
void Update()
{
// 3 - Retrieve axis information
float inputX = Input.GetAxis("Horizontal");
float inputY = Input.GetAxis("Vertical");
// 4 - Movement per direction
movement = new Vector2(
speed.x * inputX,
speed.y * inputY);
// 5 - Shooting
bool shoot = Input.GetButtonDown("Fire1");
shoot |= Input.GetButtonDown("Fire2");
// Careful: For Mac users, ctrl + arrow is a bad idea
if (shoot)
{
WeaponScript weapon = GetComponent<WeaponScript>();
if (weapon != null)
{
// false because the player is not an enemy
weapon.Attack(false);
}
}
// 6 - Make sure we are not outside the camera bounds
var dist = (transform.position - Camera.main.transform.position).z;
var leftBorder = Camera.main.ViewportToWorldPoint(
new Vector3(0, 0, dist)
).x;
var rightBorder = Camera.main.ViewportToWorldPoint(
new Vector3(1, 0, dist)
).x;
var topBorder = Camera.main.ViewportToWorldPoint(
new Vector3(0, 0, dist)
).y;
var bottomBorder = Camera.main.ViewportToWorldPoint(
new Vector3(0, 1, dist)
).y;
transform.position = new Vector3(
Mathf.Clamp(transform.position.x, leftBorder, rightBorder),
Mathf.Clamp(transform.position.y, topBorder, bottomBorder),
transform.position.z
);
}
void FixedUpdate()
{
// 5 - Move the game object
rigidbody2D.velocity = movement;
}
void OnDestroy()
{
Application.LoadLevel("gameOver");
}
}
and my player's health script
using UnityEngine;
/// <summary>
/// Handle hitpoints and damages
/// </summary>
public class HealthScript : MonoBehaviour
{
/// <summary>
/// Total hitpoints
/// </summary>
public int hp = 1;
/// <summary>
/// Enemy or player?
/// </summary>
public bool isEnemy = true;
/// <summary>
/// Inflicts damage and check if the object should be destroyed
/// </summary>
/// <param name="damageCount"></param>
public void Damage(int damageCount)
{
hp -= damageCount;
if (hp <= 0)
{
// 'Splosion!
SpecialEffectsHelper.Instance.Explosion(transform.position);
// Dead!
Destroy(gameObject);
}
}
void OnTriggerEnter2D(Collider2D otherCollider)
{
// Is this a shot?
ShotScript shot = otherCollider.gameObject.GetComponent<ShotScript>();
if (shot != null)
{
// Avoid friendly fire
if (shot.isEnemyShot != isEnemy)
{
Damage(shot.damage);
// Destroy the shot
Destroy(shot.gameObject); // Remember to always target the game object, otherwise you will just remove the script
}
}
}
}
With new UI system in Unity 4.6 it is really easy to create a health bar.
GameObject->UI->Image
Put your health bar sprite in image.
Change the Image type to Filled. Then you can play with Fill amount property and also control in through code
In your PlayerScript you retrieve the HealthScript with the following code:
HealthScript playerHealth = this.GetComponent<HealthScript>();
If you want to call methods on the Health script you would do something similar.
Health healthBar = this.GetComponent<Health>();
healthBar.modifyHealth(amountOfDamage);
This assumes all 3 scripts are on the same Game object.

Unity3D (2D) Grid Based path following and line drawing system not working

I'm currently working on a set of scripts. The collective purpose of these scripts is to create a controller object that, upon the user clicking on an object, will check if the object is a GridCell object then add it to a list of positions; the list of positions will be followed by the controller as a path.
A secondary effect of the script is that it should draw a line representing the path created by the list of positions. There are five different scripts in the entire project, here they are:
GridController.cs (Primary script)
using UnityEngine;
using System.Collections;
public class GridController : MonoBehaviour {
private RaycastHit rayhit;
public Path controllerPath;
public GLLineController lineController;
public bool playerTransforming = false;
public Vector2 currentTarget = Path.VECTORNULL;
// Use this for initialization
void Start () {
controllerPath = new Path();
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
if (RaycastHitGridcell(Camera.main.ScreenPointToRay(Input.mousePosition), out this.rayhit))
{
Vector2 tempRayhitV = new Vector2(rayhit.transform.position.x, rayhit.transform.position.y);
controllerPath.Add(tempRayhitV);
if (controllerPath.PathList2D.Count < 1)
{
lineController.lineList.Add(new Line(transform.position,
new Vector3(tempRayhitV.x, tempRayhitV.y),
Screen.width,
Screen.height,
Camera.main,
false));
}
else
{
Vector2 lastInLineList = controllerPath.PathList2D[controllerPath.PathList2D.Count - 1];
lineController.lineList.Add(new Line(new Vector3(lastInLineList.x, lastInLineList.y),
new Vector3(tempRayhitV.x, tempRayhitV.y),
Screen.width,
Screen.height,
Camera.main,
false));
}
}
}
#region tryNext
/*Vector2 nv2;
if (!playerTransforming && controllerPath.TryNext(new Vector2(transform.position.x, transform.position.y), out nv2, out this.playerTransforming))
{
this.transform.Translate(nv2.x, nv2.y, 0f);
}*/
if (!playerTransforming && controllerPath.PathList2D.Count > 1)
{
Vector2 nv2 = controllerPath.Next();
if (nv2 != Path.VECTORNULL)
{
playerTransforming = true;
currentTarget = nv2;
this.transform.Translate(new Vector3(nv2.x, nv2.y, 0f));
}
}
if (currentTarget != Path.VECTORNULL && (Mathf2.Approximately(currentTarget.x, transform.position.x, 0.001f) &&
Mathf2.Approximately(currentTarget.y, transform.position.y, 0.001f)))
{
playerTransforming = false;
currentTarget = Path.VECTORNULL;
}
#endregion
}
public static bool RaycastHitGridcell(Ray ray, out RaycastHit hit)
{
RaycastHit tHit;
if (Physics.Raycast(ray, out tHit))
{
if (tHit.transform.gameObject.tag == "GridCell")
{
hit = tHit;
return true;
}
}
hit = tHit;
return false;
}
}
Path.cs (Represents a list of positions to follow)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Path {
/// <summary>
/// List that represents a path of positions.
/// </summary>
public List<Vector2> PathList2D = new List<Vector2>();
/// <summary>
/// Instantiate a constant variable that stores the default NULL value for a vector2 x value.
/// </summary>
public const float VECTORNULL_X = float.NaN;
/// <summary>
/// Instantiate a constant variable that stores the default NULL value for a vector2 y value.
/// </summary>
public const float VECTORNULL_Y = float.NaN;
public static Vector2 VECTORNULL_V2
{
get { return new Vector2(VECTORNULL_X, VECTORNULL_Y); }
}
/// <summary>
/// Add an object to the end of the vector2 list.
/// </summary>
/// <param name="position">Object to add.</param>
public void Add(Vector2 position)
{
PathList2D.Add(position);
}
/// <summary>
/// Remove a specific object from the vector2 list.
/// </summary>
/// <param name="position">Object to remove.</param>
public void Remove(Vector2 position)
{
PathList2D.Remove(position);
}
/// <summary>
/// Remove an object at a specified index within the vector2 list.
/// </summary>
/// <param name="index">Indext to remove the object at.</param>
public void Remove(int index)
{
PathList2D.RemoveAt(index);
}
/// <summary>
/// Remove the current position.
/// </summary>
/// <returns>VECTORNULL if path isn't long enough. The next position if the path is long enough.</returns>
public Vector2 Next()
{
if (PathList2D.Count < 1)
return VECTORNULL_V2;
Vector2 nvt = PathList2D[0];
PathList2D.RemoveAt(0);
return nvt;
}
}
public class SpecialVector2
{
private float _X, _Y;
public float X
{
get { return (Null ? float.NaN : _X); }
set { _X = value; }
}
public float Y
{
get { return (Null ? float.NaN : _Y); }
set { _Y = value; }
}
public bool Null = false;
public SpecialVector2(float x, float y)
{
this._X = x;
this._Y = y;
}
public SpecialVector2(bool nullFlag)
{
this.Null = nullFlag;
}
public static SpecialVector2 TrueNull()
{
return new SpecialVector2(true);
}
}
Line.cs (Object that represents the vectors for a GL line)
using UnityEngine;
using System.Collections;
public class Line {
public Vector3 StartingVertex;
public Vector3 EndingVertex;
public Line(Vector3 starting, Vector3 ending, int xMax, int yMax, Camera viewport, bool vpCompatible = true)
{
if (!vpCompatible)
{
StartingVertex = new Vector3((starting.x - viewport.transform.position.x) / (float)xMax,
(starting.y - viewport.transform.position.y) / (float)yMax,
0);
EndingVertex = new Vector3((ending.x - viewport.transform.position.x) / (float)xMax,
(ending.y - viewport.transform.position.y) / (float)yMax,
0);
}
else
{
StartingVertex = starting;
EndingVertex = ending;
}
}
}
GLLineController.cs (Script that controls the post rendering of GL lines.)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class GLLineController : MonoBehaviour {
/// <summary>
/// Material to pass over the line.
/// </summary>
private Material mat;
/// <summary>
/// List of line objects that will represent the vectors for the GL lines.
/// </summary>
public List<Line> lineList = new List<Line>();
// Use this for initialization
void Start () {
CreateLineMaterial();
}
/// <summary>
/// Assign a basic material pass to the mat field.
/// </summary>
public void CreateLineMaterial()
{
if (!mat)
{
mat = new Material("Shader \"Lines/Colored Blended\" {" +
"SubShader { Pass { " +
" Blend SrcAlpha OneMinusSrcAlpha " +
" ZWrite Off Cull Off Fog { Mode Off } " +
" BindChannels {" +
" Bind \"vertex\", vertex Bind \"color\", color }" +
"} } }");
mat.hideFlags = HideFlags.HideAndDontSave;
mat.shader.hideFlags = HideFlags.HideAndDontSave;
}
}
// Update is called once per frame
void Update () {
}
void OnPostRender()
{
GL.PushMatrix();
mat.SetPass(0);
GL.LoadOrtho();
GL.Begin(GL.LINES);
GL.Color(Color.white);
foreach (Line l in lineList)
{
GL.Vertex(l.StartingVertex);
GL.Vertex(l.EndingVertex);
}
GL.End();
GL.PopMatrix();
}
}
Theoretically, these scripts should work semi-perfectly in union, but they don't work at all from what i can tell.
Does anybody have a better way to go about this? Otherwise, does anybody know where my error(s) is/are?
Thank you!
-Tristen H.

Allow mousepointer to be outside of screen boundaries

I'm making a game using XNA 4.0 and c#.
I just made my camera class and it's almost working as expected, except for one thing.
I can move with my mouse to rotate the camera but the problem is that when I get to the border of the screen, the mouse stops and so does the camera movement.
Is there any way to allow the mouse pointer to be outside of the screens boundaries to be able to keep tracking the pointer? Or is there any simpler way around?
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;
public class ArcBallCamera
{
private float speeder = 100;
public ArcBallCamera(float aspectRation, Vector3 lookAt)
: this(aspectRation, MathHelper.PiOver4, lookAt, Vector3.Up, 0.1f, float.MaxValue) { }
public ArcBallCamera(float aspectRatio, float fieldOfView, Vector3 lookAt, Vector3 up, float nearPlane, float farPlane)
{
this.aspectRatio = aspectRatio;
this.fieldOfView = fieldOfView;
this.lookAt = lookAt;
this.nearPlane = nearPlane;
this.farPlane = farPlane;
}
/// <summary>
/// Recreates our view matrix, then signals that the view matrix
/// is clean.
/// </summary>
public void ReCreateViewMatrix()
{
//Calculate the relative position of the camera
position = Vector3.Transform(Vector3.Backward, Matrix.CreateFromYawPitchRoll(yaw, pitch, 0));
//Convert the relative position to the absolute position
position *= zoom;
position += lookAt;
//Calculate a new viewmatrix
viewMatrix = Matrix.CreateLookAt(position, lookAt, Vector3.Up);
viewMatrixDirty = false;
}
/// <summary>
/// Recreates our projection matrix, then signals that the projection
/// matrix is clean.
/// </summary>
public void ReCreateProjectionMatrix()
{
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(fieldOfView, AspectRatio, nearPlane, farPlane);
projectionMatrixDirty = false;
}
#region HelperMethods
/// <summary>
/// Moves the camera and lookAt at to the right,
/// as seen from the camera, while keeping the same height
/// </summary>
public void MoveCameraRight(float amount)
{
Vector3 right = Vector3.Normalize(LookAt - Position); //calculate forward
right = Vector3.Cross(right, Vector3.Up); //calculate the real right
//right.Y = 0;
right.Normalize();
LookAt += right * amount;
}
/// <summary>
/// Moves the camera and lookAt forward,
/// as seen from the camera, while keeping the same height
/// </summary>
public void MoveCameraForward(float amount)
{
Vector3 forward = Vector3.Normalize(LookAt - Position);
// forward.Y = 0;
forward.Normalize();
LookAt += forward * amount;
}
/// <summary>
/// Moves the camera and lookAt up or down,
/// LOL
/// </summary>
public void MoveCameraUp(float amount)
{
Vector3 up = Vector3.Normalize(LookAt - position);
up = Vector3.Cross(up, Vector3.Left); //Calculate the REAL FUCKING UP/DOWN
up.X = 0;
up.Z = 0;
up.Normalize();
LookAt += up * amount;
}
#endregion
#region FieldsAndProperties
//We don't need an update method because the camera only needs updating
//when we change one of it's parameters.
//We keep track if one of our matrices is dirty
//and reacalculate that matrix when it is accesed.
private bool viewMatrixDirty = true;
private bool projectionMatrixDirty = true;
public float MinPitch = -MathHelper.PiOver2 + 0.3f;
public float MaxPitch = MathHelper.PiOver2 - 0.3f;
private float pitch;
public float Pitch
{
get { return pitch; }
set
{
viewMatrixDirty = true;
pitch = MathHelper.Clamp(value, MinPitch, MaxPitch);
}
}
private float yaw;
public float Yaw
{
get { return yaw; }
set
{
viewMatrixDirty = true;
yaw = value;
}
}
private float fieldOfView;
public float FieldOfView
{
get { return fieldOfView; }
set
{
projectionMatrixDirty = true;
fieldOfView = value;
}
}
private float aspectRatio;
public float AspectRatio
{
get { return aspectRatio; }
set
{
projectionMatrixDirty = true;
aspectRatio = value;
}
}
private float nearPlane;
public float NearPlane
{
get { return nearPlane; }
set
{
projectionMatrixDirty = true;
nearPlane = value;
}
}
private float farPlane;
public float FarPlane
{
get { return farPlane; }
set
{
projectionMatrixDirty = true;
farPlane = value;
}
}
public float MinZoom = 1;
public float MaxZoom = float.MaxValue;
private float zoom = 1;
public float Zoom
{
get { return zoom; }
set
{
viewMatrixDirty = true;
zoom = MathHelper.Clamp(value, MinZoom, MaxZoom);
}
}
private Vector3 position;
public Vector3 Position
{
get
{
if (viewMatrixDirty)
{
ReCreateViewMatrix();
}
return position;
}
}
private Vector3 lookAt;
public Vector3 LookAt
{
get { return lookAt; }
set
{
viewMatrixDirty = true;
lookAt = value;
}
}
#endregion
#region ICamera Members
public Matrix ViewProjectionMatrix
{
get { return ViewMatrix * ProjectionMatrix; }
}
private Matrix viewMatrix;
public Matrix ViewMatrix
{
get
{
if (viewMatrixDirty)
{
ReCreateViewMatrix();
}
return viewMatrix;
}
}
private Matrix projectionMatrix;
public Matrix ProjectionMatrix
{
get
{
if (projectionMatrixDirty)
{
ReCreateProjectionMatrix();
}
return projectionMatrix;
}
}
#endregion
}
You can reset the mouse position for every frame.
Example:
// Center of the window
var resetPosition = new Point(WindowWidth / 2, WindowHeight / 2);
// Get the movement since the last frame
var mouseState = Mouse.GetState();
var mousePosition = new Point(mouseState.X, mouseState.Y);
var delta = mousePosition - resetPosition;
// Reset the mouse position
Mouse.SetPosition(resetPosition.X, resetPosition.Y);
// Use the delta
RotateCamera(delta);

Sprites and Spawning

I've got a ship that's spawning sprites. There are two types: railgun rounds and missiles. The missiles fire off properly, but the railgun rounds always spawn about one hundred pixels in front of the ship (or at least, it seems to). I'm not sure why this is happening. Also, there are two turrets, when it fires out of one, it's supposed to set a boolean value to true to make it fire out of the other one; when it fires out of that one, it sets the boolean back to false and so on. It always fires out of the first one. Again, no idea why. I've been banging my head against this all day. Here's my code:
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 ShipBattle.Classes.Ships;
using ShipBattle.Classes.Ships.Fighters;
using ShipBattle.Classes.Ships.Projectiles;
using ShipBattle.Classes.Ships.Projectiles.Tauri;
namespace ShipBattle.Classes.Ships.Fighters
{
public class F302 : Ship
{
const double missileMinimumFiringArc = Utilities.NINETY_DEGREES / 2;
const double missileMaximumFiringArc = Utilities.NINETY_DEGREES + (Utilities.NINETY_DEGREES / 2);
const double railgunMinimumFiringArc = 1.5;
const double railgunMaximumFiringArc = 1.6;
const double MISSILES_ROF = 30.0;
protected List<double> CooldownLeft = new List<double>();
private ContentManager content;
public event ShipFired WeaponFired;
public List<NaquadahEnhancedMissile> missiles;
public List<RailgunRound> railgunRounds;
public int[] MissileAmmo { get; set; }
public int[] RailgunAmmo { get; set; }
//Determines which missile/railgun to fire
bool leftMissile = true;
bool leftRailgun = true;
public F302(Vector2 position, ContentManager Content)
{
content = Content;
Texture = content.Load<Texture2D>(#"Textures\Ships\Tauri\Fighters\F302");
Position = position;
Rotation = 0;
#region Physics Stuff
mass = 19200;
force = 76.3f;
acceleration = (force * 1000) / mass;
maxSpeed = Utilities.GetVelocity(acceleration);
#endregion
#region Hull & Shielding
HullIntegrity = 10;
ShieldStrength = 0;
#endregion
#region Weapons!!!
/*
* [0] = Port Missile
* [1] = Starboard Missile
* [2] = Port Railgun
* [3] = Starboard Railgun
*/
//Setup
missiles = new List<NaquadahEnhancedMissile>();
railgunRounds = new List<RailgunRound>();
MissileAmmo = new int[2];
RailgunAmmo = new int[2];
//Port Missile
WeaponRatesOfFire.Add(MISSILES_ROF);
CooldownLeft.Add(0);
WeaponsEnplacements.Add(new Vector2(14, 5));
WeaponEmplacementOffsets.Add(new Vector2(14, 5));
MissileAmmo[0] = 2;
//Starboard Missile
WeaponRatesOfFire.Add(MISSILES_ROF);
CooldownLeft.Add(0);
WeaponsEnplacements.Add(new Vector2(35, 5));
WeaponEmplacementOffsets.Add(new Vector2(35, 5));
MissileAmmo[1] = 2;
//Port Railgun
WeaponRatesOfFire.Add(7.2);
CooldownLeft.Add(0);
WeaponsEnplacements.Add(new Vector2(24, 0));
WeaponEmplacementOffsets.Add(new Vector2(24, 0));
RailgunAmmo[0] = 10000;
//Starboard Railgun
WeaponRatesOfFire.Add(7.2);
CooldownLeft.Add(0);
WeaponsEnplacements.Add(new Vector2(26, 0));
WeaponEmplacementOffsets.Add(new Vector2(26, 0));
RailgunAmmo[1] = 10000;
#endregion
}
protected override void UpdateProjectiles(Vector2 pos)
{
for (int i = 0; i < missiles.Count; i++)
if (missiles[i].Remove)
missiles.RemoveAt(i);
for (int i = 0; i < railgunRounds.Count; i++)
if (railgunRounds[i].Remove)
railgunRounds.RemoveAt(i);
foreach (NaquadahEnhancedMissile nem in missiles)
nem.Update(enemyPos);
foreach (RailgunRound rr in railgunRounds)
rr.Update(enemyPos);
}
protected override void DrawProjectiles(SpriteBatch spriteBatch)
{
foreach (NaquadahEnhancedMissile nem in missiles)
nem.Draw(spriteBatch);
foreach (RailgunRound rr in railgunRounds)
rr.Draw(spriteBatch);
}
protected override void CheckTarget(Ship target)
{
enemyPos = target.Position;
double distance = Vector2.Distance(Position, target.Position);
Vector2 vector1 = Vector2.Normalize(Position - target.Position);
Vector2 vector2 = new Vector2((float)Math.Cos(Rotation), (float)Math.Sin(Rotation));
double angle = Math.Acos(Vector2.Dot(vector1, vector2));
if (angle > missileMinimumFiringArc && angle < missileMaximumFiringArc)
if (distance < 500)
if (((target.HullIntegrity + target.ShieldStrength) - 10) <= 0)
FireMissiles();
if (angle > railgunMinimumFiringArc && angle < railgunMaximumFiringArc)
FireRailguns();
}
protected void FireMissiles()
{
if (leftMissile)
{
if (CooldownLeft[0] <= 0)
{
if (MissileAmmo[0] > 0)
{
NaquadahEnhancedMissile nem = new NaquadahEnhancedMissile(WeaponsEnplacements[0], Rotation, content);
nem.hit += new ProjectileHit(nem_hit);
missiles.Add(nem);
CooldownLeft[0] = WeaponRatesOfFire[0];
CooldownLeft[1] = WeaponRatesOfFire[1];
MissileAmmo[0]--;
leftMissile = false;
}
}
}
else
if (CooldownLeft[1] <= 0)
{
if (MissileAmmo[1] > 0)
{
NaquadahEnhancedMissile nem = new NaquadahEnhancedMissile(WeaponsEnplacements[1], Rotation, content);
nem.hit += new ProjectileHit(nem_hit);
missiles.Add(nem);
CooldownLeft[0] = WeaponRatesOfFire[0];
CooldownLeft[1] = WeaponRatesOfFire[1];
MissileAmmo[1]--;
leftMissile = true;
}
}
}
private void FireRailguns()
{
if (leftRailgun)
{
if (CooldownLeft[2] <= 0)
{
if (RailgunAmmo[0] > 0)
{
RailgunRound rgr = new RailgunRound(WeaponsEnplacements[2], Rotation, content);
rgr.hit += new ProjectileHit(nem_hit);
railgunRounds.Add(rgr);
CooldownLeft[2] = WeaponRatesOfFire[2];
CooldownLeft[3] = WeaponRatesOfFire[3];
RailgunAmmo[0]--;
leftRailgun = false;
}
}
}
else
if (CooldownLeft[3] <= 0)
{
if (RailgunAmmo[1] > 0)
{
RailgunRound rgr = new RailgunRound(WeaponsEnplacements[3], Rotation, content);
rgr.hit += new ProjectileHit(nem_hit);
railgunRounds.Add(rgr);
CooldownLeft[2] = WeaponRatesOfFire[2];
CooldownLeft[3] = WeaponRatesOfFire[3];
MissileAmmo[1]--;
leftRailgun = true;
}
}
}
protected override void Cooldown()
{
for (int f = 0; f < CooldownLeft.Count; f++)
CooldownLeft[f]--;
}
private void nem_hit(Projectile p, EventArgs e)
{
if (p is NaquadahEnhancedMissile)
{
p.Remove = true;
if (targetShip.ShieldStrength > 0)
targetShip.ShieldStrength -= p.Damage;
else
targetShip.HullIntegrity -= p.Damage;
}
else if (p is RailgunRound)
{
p.Remove = true;
if (targetShip.ShieldStrength > 0)
targetShip.ShieldStrength -= p.Damage / 4;
else
targetShip.HullIntegrity -= p.Damage;
}
}
protected override void CleanupProjectiles()
{
missiles.Clear();
railgunRounds.Clear();
}
}
}
And here's the code for the ship class this all inherits from:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ShipBattle.Classes.Ships.Projectiles;
using ShipBattle.Classes.Ships.Projectiles.Tauri;
namespace ShipBattle.Classes.Ships
{
public abstract class Ship
{
public Texture2D Texture { get; set; }
public Vector2 Position
{
get
{
return _position;
}
set
{
_position = value;
}
}
public float Rotation { get; set; }
private Vector2 _position;
protected Ship targetShip;
protected Vector2 enemyPos;
#region Health & Shielding
public float HullIntegrity { get; set; }
public float ShieldStrength { get; set; }
public bool Remove { get; set; }
#endregion
#region Guns
protected List<Vector2> WeaponsEnplacements = new List<Vector2>();
protected List<Vector2> WeaponEmplacementOffsets = new List<Vector2>();
protected List<double> WeaponRatesOfFire = new List<double>();
/// <summary>
/// The rates of fire for all weapons, represented in terms of the delay between frames
/// </summary>
#endregion
#region Targeting Logic
bool hasTarget = false;
protected int targetHashCode;
Vector2 targetShipPosition;
Ship target;
bool evasive = false;
bool hasRandomTrajectory = false;
bool reachedBounds = false;
bool followingRandom = false;
int timeToFaffAbout = 360;
double randomRotation;
#endregion
#region Physics Stuff
float angleA, b, a, speed = 0;
double turningRadius = 10 * (Math.PI / 180);
//Acceleration
protected int mass; // kg
protected float force; // kN, thruster power
protected float acceleration; // m/s^2
//Velocity
protected float maxSpeed; // m/s, calculated using 30-second burn
protected float initialSpeed = 0;
protected float finalSpeed = 0;
protected float time = 0.016666f;
#endregion
public void Update(List<Ship> ships)
{
if (timeToFaffAbout >= 0)
{
timeToFaffAbout = 360;
followingRandom = false;
}
if (!hasTarget)
{
targetShip = GetTarget(ships);
hasTarget = true;
}
else
{
if (targetShip != null)
{
if (Vector2.Distance(Position, targetShip.Position) < 75)
evasive = true;
else
evasive = false;
if (evasive)
{
if (!hasRandomTrajectory)
{
Random random = new Random();
randomRotation = random.Next((int)(Math.PI * 100));
double negative = random.Next(2);
if (negative == 1)
randomRotation *= -1;
Rotation = (float)randomRotation;
hasRandomTrajectory = true;
}
}
else
{
if (!followingRandom)
{
//Rotate the sprite using the turning radius
Rotation = Utilities.TurnToFace(Position, new Vector2(targetShip.Position.X, targetShip.Position.Y), (float)Rotation, (float)turningRadius);
}
}
KeepOnTheScreen();
//Move the sprite, using KINEMATIC PHYSICS, ***!!! -->goes in the direction set by the rotation algorithm
Move();
CheckTarget(targetShip);
UpdateProjectiles(targetShip.Position);
//Stop targeting a dead enemy
if (targetShip.HullIntegrity <= 0)
hasTarget = false;
}
}
//Recalculate the List<Vector2> weapons enplacements based on the current rotation angle
RecalculateWeaponsPositions();
//Cooldown the guns
Cooldown();
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, Position, null, Color.White, Rotation, new Vector2(Texture.Width / 2, Texture.Height / 2), 0.5f,
SpriteEffects.None, 0.0f);
if (hasTarget)
DrawProjectiles(spriteBatch);
}
/// <summary>
/// Uses trig and the thruster power to move the ship. b is the y distance to move, a is the x distance to move
/// </summary>
private void Move()
{
if (finalSpeed < maxSpeed)
finalSpeed = speed + (acceleration * time);
angleA = Rotation;
b = (float)Math.Cos(angleA) * finalSpeed;
a = (float)Math.Sin(angleA) * finalSpeed;
_position.Y -= b;
_position.X += a;
speed = finalSpeed;
}
/// <summary>
/// Acquires the closes enemy ship
/// </summary>
/// <param name="ships">The ships to search through</param>
/// <returns></returns>
private Ship GetTarget(List<Ship> ships)
{
CleanupProjectiles();
Ship rVal = null;
int distance = int.MaxValue;
float c;
foreach (Ship ship in ships)
{
c = Vector2.Distance(Position, ship.Position);
if (c < distance)
rVal = ship;
}
return rVal;
}
/// <summary>
/// Reorients the positions of all the weapon positions on this ship
/// </summary>
private void RecalculateWeaponsPositions()
{
for (int i = 0; i < WeaponsEnplacements.Count; i++)
{
WeaponsEnplacements[i] = RotateWeapons(WeaponEmplacementOffsets[i]);
}
}
/// <summary>
/// Recalculates the positions of the weapons on this ship based off their default offset and the current angle
/// </summary>
/// <param name="weapon">The weapon position to recalculate</param>
/// <param name="offset">The default offset of that weapon</param>
private Vector2 RotateWeapons(Vector2 offset)
{
Quaternion rotation = Quaternion.CreateFromAxisAngle(Vector3.Backward, (float)Rotation);
return Vector2.Transform(offset, rotation) + Position;
}
/// <summary>
/// Keeps the ship on the screen
/// </summary>
private void KeepOnTheScreen()
{
if (Position.X > 1019 || Position.X < 5 || Position.Y > 761 || Position.Y < 5)
reachedBounds = true;
else
reachedBounds = false;
if (reachedBounds)
{
followingRandom = true;
if (!followingRandom)
Rotation = Utilities.TurnToFace(Position, new Vector2(1024 / 2, 768 / 2), Rotation, (float)turningRadius);
else
timeToFaffAbout--;
}
}
/// <summary>
/// Checks to see if the target ship is within weapons range
/// </summary>
/// <param name="target"></param>
protected abstract void CheckTarget(Ship target);
/// <summary>
/// Decrements the cooldown of all weapons
/// </summary>
protected abstract void Cooldown();
protected abstract void UpdateProjectiles(Vector2 pos);
protected abstract void DrawProjectiles(SpriteBatch spriteBatch);
protected abstract void CleanupProjectiles();
}
}
If anyone can help me with this, I'd be really appreciative. Thank you!
Why does FireRailguns() execute MissileAmmo[1]--; ?

Categories