I have written a script for a procedural cube. Basically I want to make a building whose width, length and height I can control through parameters. So by changing parameters I can make different shapes like windows and door and roof and many more. But I don't have any idea how to do that. How to reuse this script for different shapes?
using UnityEngine;
public class genralWindows: MonoBehaviour
{
public float height = 0.8 f;
public float width = 0.6 f;
public float length = 0;
void Start()
{
cube();
gameObject.GetComponent < Renderer > ().material.color = Color.white;
}
public void cube()
{
MeshFilter mf1 = GetComponent < MeshFilter > ();
Mesh mesh1 = mf1.mesh;
//vertices
Vector3[] vertices = new Vector3[]
{
//front face
new Vector3(-width, height, length), //left top front, 0
new Vector3(width, height, length), //right top front, height
new Vector3(-width, -height, length), //left bottom front, 2
new Vector3(width, -height, length), //right bottom front, width
//BACK FACE
new Vector3(width, height, -length), //right top back, 4
new Vector3(-width, height, -length), //left top back, length
new Vector3(width, -height, -length), //right bottom back, 6
new Vector3(-width, -height, -length), //left bottom back, 7
//LEFT FACE
new Vector3(-width, height, -length), //left top back,width
new Vector3(-width, height, length), //left top front,9
new Vector3(-width, -height, -length), //left bottom back,height0,
new Vector3(-width, -height, length), //left bottom front,heightheight
//RIGHT FACE
new Vector3(width, height, length), //right top front height2
new Vector3(width, height, -length), //right top back heightwidth
new Vector3(width, -height, length), //right bottom front height4
new Vector3(width, -height, -length), //right bottom back heightheight
//TOP FACE
new Vector3(-width, height, -length), //left top back height6
new Vector3(width, height, -length), //right top back height7
new Vector3(-width, height, length), //left top front heightwidth
new Vector3(width, height, length), //right top front height9
//BOTTOM FACE
new Vector3(-width, -height, length), //left bottom front 20
new Vector3(width, -height, length), //right bottom front 2height
new Vector3(-width, -height, -length), //left bottom back 22
new Vector3(width, -height, -length), //right bottom back 2width
};
//triangles// 3 points clockwise determines which side is visible
int[] triangles = new int[]
{
//front face
0,
2,
3, //first triangle
3,
1,
0, //second triangle
//back face
4,
6,
7, //first triangle
7,
5,
4, //second triangle
//left face
8,
10,
11, //first triangle
11,
9,
8, //second triangle
//right face
12,
14,
15, //first triangle
15,
13,
12, //second triangle
//top face
16,
18,
19, //first triangle
19,
17,
16, //second triangle
//bottom face
20,
22,
23, //first triangle
23,
21,
20 //second triangle
};
//UVs
Vector2[] uvs1 = new Vector2[]
{
//front face// 0,0 is bottom left, 1,1 is top right
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0)
};
mesh1.Clear();
mesh1.vertices = vertices;
mesh1.triangles = triangles;
mesh1.uv = uvs1;
mesh1.RecalculateNormals();
}
// Update is called once per frame
void Update()
{
cube();
}
}
You need to use inheritance.
Make a class Cube like this:
public class Cube:MonoBehaviour{
}
Then make other classes like this:
public class Door:Cube{
}
You can get more details here: https://unity3d.com/learn/tutorials/topics/scripting/inheritance
You don't really need to program the dimensions of a cube or other elements in your scene from scratch. Unity already offers some primitives you can instantiate in your game, and access their attributes from your script to modify their values.
In case you want to create an Enviroment programatically using GameObjects with primitives ( like cubes, spheres...) or custom GameObjects (like 3D models you created on Blender) you can do something like this:
//You will need to pass in the inspector a GameObject as parameter in the correct field
public GameObject customGameObject;
void Start()
{
generateEnviroment()
}
void generateEnviroment()
{
//You instantiate a GameObject of type cube
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
//You change its position
cube.transform.position = new Vector3(0, 0.5F, 0);
// Widen the object by 0.1
cube.transform.localScale += new Vector3(0.1F, 0, 0);
//Change material properties, assuming it has a material component
Renderer rend = cube.GetComponent<Renderer>();
rend.material.shader = Shader.Find("Specular");
rend.material.SetColor("_SpecColor", Color.red);
//In case you want to add other type of GameObject, like a car or sth you have created:
GameObject myGameObject = GameObject.Instantiate (customGameObject);
}
You can make that function as long as complex as you want, just being tidy with names.
https://docs.unity3d.com/ScriptReference/GameObject.CreatePrimitive.html
Related
I have a class called Cube in which I render a basic cube to the screen. I've got it working as far as rendering a basic cube of any scale at origin 0, 0, 0. However, if I want to move the cube, scale any of its axes, or rotate the cube; I have no idea where to begin since I have to achieve this within a Vertex object.
struct Vertex {
Vector3 Position;
Vector3 Normal;
Vector2 TextureUV;
Color Color;
}
To render a cube of size 1000000 I simply fill the Position properties with that value (with regards to negative and positive values to generate the faces).
new Vertex(new Vector3(-1000000, -1000000, -1000000), new Vector3(-1, -1, -1), Color.White);
Cube has four properties:
Position (Vector3).
Scale (Vector3).
Rotation (Vector3).
Color (SharpDX.Color).
My question is, as I am specifying Vertex locations, how can I calculate the new position when rotation and position are applied?
I attempted basic subtraction and addition which simply scales the cube differently and the origin remains at 0, 0, 0 (please don't mind the shorthand).
new Vertex(new Vector3(P.X - S.X, P.Y - S.Y, P.Z - S.Z), new Vector3(1, 1, 1), Color.White);
The above isn't the exact code as it is on a different computer currently.
If you need additional details, please let me know and I will clarify.
The Question
How can I set the position of the vertices based on the supplied position, scale, and rotation vectors?
Test Case
The following test cases are for position only and are to show you how I will test the answers given.
// Renders at origin.
Cube myCube = new Cube(new Vector3(0, 0, 0), new Vector3(100, 100, 100), Color.White);
// Renders to the left.
Cube myCubeLeft = new Cube(new Vector3(-250, 0, 0), new Vector3(100, 100, 100), Color.White);
// Renders to the right.
Cube myCubeRight = new Cube(new Vector3(250, 0, 0), new Vector3(100, 100, 100), Color.White);
// Renders above.
Cube myCubeUp = new Cube(new Vector3(0, -250, 0), new Vector3(100, 100, 100), Color.White);
// Renders below.
Cube myCubeDown = new Cube(new Vector3(0, 250, 0), new Vector3(100, 100, 100), Color.White);
I will add rotation and scaling test cases later if needed.
I want to check in Unity if the device has been rotated on all of it's axis.
So, I am reading the rotation of all the axis.
What should I do in order to validate for example that the user has "flipped" his device over the X-axis? I need to check the value, and see that they contain 0, 90, 180 and 270 degrees in a loop.
Here is part of my code:
void Update () {
float X = Input.acceleration.x;
float Y = Input.acceleration.y;
float Z = Input.acceleration.z;
xText.text = ((Mathf.Atan2(Y, Z) * 180 / Mathf.PI)+180).ToString();
yText.text = ((Mathf.Atan2(X, Z) * 180 / Mathf.PI)+180).ToString();
zText.text = ((Mathf.Atan2(X, Y) * 180 / Mathf.PI)+180).ToString();
}
The accelerometer only tells you if the acceleration of the device changes. So you will have values if the device started moving, or stopped moving. You can't retrieve its orientation from that.
Instead you need to use the gyroscope of the device. Most device have one nowadays.
Fortunately, Unity supports the gyroscope through the Gyroscope class
Simply using
Input.gyro.attitude
Will give you the orientation of the device in space, in the form of a quaternion.
To check the angles, use the eulerAngles function, for instance, is the device flipped in the x axis:
Vector3 angles = Input.gyro.attitude.eulerAngles;
bool xFlipped = angles.x > 180;
Be careful, you might have to invert some values if you want to apply the rotation in Unity (because it depend which orientation the devices uses for positive values, left or right)
// The Gyroscope is right-handed. Unity is left handed.
// Make the necessary change to the camera.
private static Quaternion GyroToUnity(Quaternion q)
{
return new Quaternion(q.x, q.y, -q.z, -q.w);
}
Here is the full example from the doc (Unity version 2017.3), in case the link above is broken. It shows how to read value from the gyroscope, and apply them to an object in Unity.
// Create a cube with camera vector names on the faces.
// Allow the device to show named faces as it is oriented.
using UnityEngine;
public class ExampleScript : MonoBehaviour
{
// Faces for 6 sides of the cube
private GameObject[] quads = new GameObject[6];
// Textures for each quad, should be +X, +Y etc
// with appropriate colors, red, green, blue, etc
public Texture[] labels;
void Start()
{
// make camera solid colour and based at the origin
GetComponent<Camera>().backgroundColor = new Color(49.0f / 255.0f, 77.0f / 255.0f, 121.0f / 255.0f);
GetComponent<Camera>().transform.position = new Vector3(0, 0, 0);
GetComponent<Camera>().clearFlags = CameraClearFlags.SolidColor;
// create the six quads forming the sides of a cube
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quads[0] = createQuad(quad, new Vector3(1, 0, 0), new Vector3(0, 90, 0), "plus x",
new Color(0.90f, 0.10f, 0.10f, 1), labels[0]);
quads[1] = createQuad(quad, new Vector3(0, 1, 0), new Vector3(-90, 0, 0), "plus y",
new Color(0.10f, 0.90f, 0.10f, 1), labels[1]);
quads[2] = createQuad(quad, new Vector3(0, 0, 1), new Vector3(0, 0, 0), "plus z",
new Color(0.10f, 0.10f, 0.90f, 1), labels[2]);
quads[3] = createQuad(quad, new Vector3(-1, 0, 0), new Vector3(0, -90, 0), "neg x",
new Color(0.90f, 0.50f, 0.50f, 1), labels[3]);
quads[4] = createQuad(quad, new Vector3(0, -1, 0), new Vector3(90, 0, 0), "neg y",
new Color(0.50f, 0.90f, 0.50f, 1), labels[4]);
quads[5] = createQuad(quad, new Vector3(0, 0, -1), new Vector3(0, 180, 0), "neg z",
new Color(0.50f, 0.50f, 0.90f, 1), labels[5]);
GameObject.Destroy(quad);
}
// make a quad for one side of the cube
GameObject createQuad(GameObject quad, Vector3 pos, Vector3 rot, string name, Color col, Texture t)
{
Quaternion quat = Quaternion.Euler(rot);
GameObject GO = Instantiate(quad, pos, quat);
GO.name = name;
GO.GetComponent<Renderer>().material.color = col;
GO.GetComponent<Renderer>().material.mainTexture = t;
GO.transform.localScale += new Vector3(0.25f, 0.25f, 0.25f);
return GO;
}
protected void Update()
{
GyroModifyCamera();
}
protected void OnGUI()
{
GUI.skin.label.fontSize = Screen.width / 40;
GUILayout.Label("Orientation: " + Screen.orientation);
GUILayout.Label("input.gyro.attitude: " + Input.gyro.attitude);
GUILayout.Label("iphone width/font: " + Screen.width + " : " + GUI.skin.label.fontSize);
}
/********************************************/
// The Gyroscope is right-handed. Unity is left handed.
// Make the necessary change to the camera.
void GyroModifyCamera()
{
transform.rotation = GyroToUnity(Input.gyro.attitude);
}
private static Quaternion GyroToUnity(Quaternion q)
{
return new Quaternion(q.x, q.y, -q.z, -q.w);
}
}
I'm trying to make a cooldown visual for my game when actions are used. I want the button that I have that is the action to be filled with a grayish semi-transparent color that "unwinds" clockwise (if that makes sense). Games like World of Warcraft do this where the time it takes for the cooldown is the time the angle of the unwinding takes. You can see an example here. In this picture the cooldown is more than 1/2 way finished.
http://www.vbforums.com/attachment.php?attachmentid=101705&stc=1&d=1372575930
I'm playing around with arc drawing but this doesn't give me what I'm after.
if (globalCD)
{
Pen p = new Pen(Color.FromArgb(125, 255, 0, 0), 10);
//e.Graphics.DrawLine(p, new Point(0, 0), new Point(10, 10));
e.Graphics.DrawArc(p, new Rectangle(0, 0, 64, 64), 270, 270);
}
In general, the Graphics class has a FillX method for each DrawX method. In this case the result is sufficiently different that the names actually change a bit, but you likely want the FillPie method.
if (globalCD)
{
Pen p = new Pen(Color.FromArgb(125, 255, 0, 0), 10);
//e.Graphics.DrawLine(p, new Point(0, 0), new Point(10, 10));
e.Graphics.FillPie(p, new Rectangle(0, 0, 64, 64), 270, 270);
}
How do you draw shapes, such as Rectangles and Circles, in MonoGame without having to save the a predrawn shape in the Content folder?
DrawRectangle() and DrawEllipse() are for Windows Form and do not work in OpenGL, which is what I am using.
Use 3D primitives and a 2D projection
Here's a simple example with explanations
I define a 10x10 rectangle and set the world matrix to make it look like a 2D projection :
Note : the BasicEffect is what draws your primitive
protected override void LoadContent()
{
_vertexPositionColors = new[]
{
new VertexPositionColor(new Vector3(0, 0, 1), Color.White),
new VertexPositionColor(new Vector3(10, 0, 1), Color.White),
new VertexPositionColor(new Vector3(10, 10, 1), Color.White),
new VertexPositionColor(new Vector3(0, 10, 1), Color.White)
};
_basicEffect = new BasicEffect(GraphicsDevice);
_basicEffect.World = Matrix.CreateOrthographicOffCenter(
0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
}
Then I draw the whole thing :D
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
EffectTechnique effectTechnique = _basicEffect.Techniques[0];
EffectPassCollection effectPassCollection = effectTechnique.Passes;
foreach (EffectPass pass in effectPassCollection)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineStrip, _vertexPositionColors, 0, 4);
}
base.Draw(gameTime);
}
There you have your rectangle !
Now this is just the tip the of the iceberg,
To draw filled rectangles : draw 2 triangle primitives
For an ellipse/circle see these : Draw an Ellipse in XNA and Draw simple circle in XNA
Or as mentioned in one of the posts above you could use a shader that does it instead ...
I needed to draw a Superellipse a while ago and ended up sketching this shader :
Drawing a SuperEllipse in HLSL
As you can see in the post a Superellipse not only draws ellipse but also other shapes and maybe even circles (I did not test) so you might be interested in it.
Ultimately you will want some class/methods to hide all these details so you just have to invoke something like DrawCircle().
Tip : by posting # https://gamedev.stackexchange.com/ you will likely get more answers for Monogame-related questions
:D
If you need to create a rectangle in 2D you can just do this:
Color[] data = new Color[rectangle.Width * rectangle.Height];
Texture2D rectTexture = new Texture2D(GraphicsDevice, rectangle.Width, rectangle.Height);
for (int i = 0; i < data.Length; ++i)
data[i] = Color.White;
rectTexture.SetData(data);
var position = new Vector2(rectangle.Left, rectangle.Top);
spriteBatch.Draw(rectTexture, position, Color.White);
Might be a tad bit easier than Aybe's answer in some situations. This creates a solid rectangle.
I found a simple solution for drawing filled and non-filled shapes, I don't know if it's power consuming or not, but here it is anyway:
{
//Filled
Texture2D _texture;
_texture = new Texture2D(graphicsDevice, 1, 1);
_texture.SetData(new Color[] { Color.White });
spriteBatch.Draw(_texture, Rect, Color.White);
}
{
//Non filled
Texture2D _texture;
_texture = new Texture2D(graphicsDevice, 1, 1);
_texture.SetData(new Color[] { Color.White });
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, Rect.Width, 1), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Right, Rect.Top, 1, Rect.Height), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Bottom, Rect.Width, 1), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, 1, Rect.Height), Color.White);
}
Sorry about all of the code, but I am completely new to Visual C# and XNA.
This program is out of Learning XNA 4.0 by Aaron Reed. My professor modified some of the stuff its supposed to do (the book covers some of this but not all of it). Most of the code is copied from the book.
These are the minimum requirements for the finished product:
You may use any 2 images in place of 3 Rings and Skull ball (or you can still use the same if you wish) – one is a player (3 Rings) and the other is a participant (also called an enemy)
The player sprite can move only using the Arrow Keys (Mouse is not activated)
The participant sprites are automated they move freely (randomly if you wish) and they bounce off the boundaries (in any manner you choose to)
At the beginning of the game there are 1 player and 5 participant sprites
The game lasts for exactly 120 seconds, at the end of the game if the player sprite has destroyed all the participant (enemy sprites) on the screen print a message indicating the player wins; otherwise print a message that the player loses
Every 10 seconds a new incarnation of an enemy sprite emerges at any location
The player sprite can destroy an enemy sprite only when it collides AND the “A” key is pressed at the same time. If the “A” key is pressed without a collision then 2 incarnations of the enemy occurs
The enemy sprites must move at a reasonable speed (not very slow I mean) for the game to be meaningful
You need to have some sounds in your program – a background sound that always plays, a sound that plays when an enemy is destroyed, a different sound when the player fires but the enemy does not get destroyed because there was no collision, a sound when a new enemy emerges (every 10 seconds)
I'm trying to make the enemies (skullballs) evade the player (threerings) but the enemies either don't respond on all sides (the player is on the right or left and the enemy doesn't evade until the player is above or below), and when the enemies do evade, they disappear offscreen shaking (they just suddenly go straight up or down and they're shaking rapidly.
When the new enemy spawns after 10 seconds, starting from the top-left corner, it bounces off the bottom wall and then disappears offscreen when it goes back up.
The skull also doesn't spawn randomly around the screen after 10 seconds.
Also I don't know how to make 2 more enemies spawn when the A button is pressed with no collision.
SpriteManager.cs
namespace Assignment_2
{
public class SpriteManager : Microsoft.Xna.Framework.DrawableGameComponent
{
//SpriteBatch for drawing
SpriteBatch spriteBatch;
//A sprite for the player and a list of automated sprites
UserControlledSprite player;
List<Sprite> spriteList = new List<Sprite>();
int enemySpawnMinMilliseconds = 10000;
int enemySpawnMaxMilliseconds = 10000;
int enemyMinSpeed = 10;
int enemyMaxSpeed = 10;
int nextSpawnTime = 0;
public SpriteManager(Game game)
: base(game)
{
// TODO: Construct any child components here
}
public override void Initialize()
{
// TODO: Add your initialization code here
ResetSpawnTime();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(Game.GraphicsDevice);
//Load the player sprite
player = new UserControlledSprite(
Game.Content.Load<Texture2D>(#"Images/threerings"),
Vector2.Zero, new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(6, 6));
//Load several different automated sprites into the list to test
//spriteList.Add(new AutomatedSprite(
// Game.Content.Load<Texture2D>(#"Images/skullball"),
// new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0),
// new Point(6, 8), new Vector2(3, 0), "skullcollision"));
//spriteList.Add(new AutomatedSprite(
// Game.Content.Load<Texture2D>(#"Images/skullball"),
// new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0),
// new Point(6, 8), new Vector2(-2, 0), "skullcollision"));
////spriteList.Add(new AutomatedSprite(
//// Game.Content.Load<Texture2D>(#"Images/skullball"),
//// new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0),
//// new Point(6, 8), new Vector2(3, 4), "skullcollision"));
////spriteList.Add(new AutomatedSprite(
//// Game.Content.Load<Texture2D>(#"Images/skullball"),
//// new Vector2(300, 400), new Point(75, 75), 10, new Point(0, 0),
//// new Point(6, 8), new Vector2(0, -3), "skullcollision"));
////spriteList.Add(new AutomatedSprite(
//// Game.Content.Load<Texture2D>(#"Images/skullball"),
//// new Vector2(200, 300), new Point(75, 75), 10, new Point(0, 0),
//// new Point(6, 8), new Vector2(-3, 7), "skullcollision"));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(#"Images/skullball"),
new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(3, 0), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(#"Images/skullball"),
new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(-2, 0), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(#"Images/skullball"),
new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(3, 4), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(#"Images/skullball"),
new Vector2(300, 400), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(0, -3), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(#"Images/skullball"),
new Vector2(200, 300), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(-3, 7), "skullcollision", this, .75f, 150));
base.LoadContent();
}
public override void Update(GameTime gameTime)
{
nextSpawnTime -= gameTime.ElapsedGameTime.Milliseconds;
if (nextSpawnTime < 0)
{
SpawnEnemy();
//reset spawn timer
ResetSpawnTime();
}
// Update player
player.Update(gameTime, Game.Window.ClientBounds);
// Update all sprites
for (int i = 0; i < spriteList.Count; ++i)
{
Sprite s = spriteList[i];
s.Update(gameTime, Game.Window.ClientBounds);
// Check for collisions
if (s.collisionRect.Intersects(player.collisionRect) && (Keyboard.GetState().IsKeyDown(Keys.A)))
{
// Play collision sound
if (s.collisionCueName != null)
((Game1)Game).PlayCue(s.collisionCueName);
// Remove collided sprite from the game
spriteList.RemoveAt(i);
--i;
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
// Draw the player
player.Draw(gameTime, spriteBatch);
// Draw all sprites
foreach (Sprite s in spriteList)
s.Draw(gameTime, spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
// Return current position of the player sprite
public Vector2 GetPlayerPosition()
{
return player.GetPosition;
}
private void SpawnEnemy()
{
Vector2 speed = Vector2.Zero;
Vector2 position = Vector2.Zero;
// Default frame size
Point frameSize = new Point(75, 75);
// Create the sprite. NOTE: This sprite bounces off the bottom wall then goes back and disappears offscreen
spriteList.Add(
new EvadingSprite(Game.Content.Load<Texture2D>(#"images\skullball"),
position, new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(3, 4), "skullcollision", this, .75f, 150));
}
private void ResetSpawnTime()
{
nextSpawnTime = ((Game1)Game).rnd.Next(
enemySpawnMinMilliseconds,
enemySpawnMaxMilliseconds);
}
}
}
EvadingSprite
class EvadingSprite : Sprite
{
// Save a reference to the sprite manager to
// use to get the player position
SpriteManager spriteManager;
// Variables to delay evasion until player is close
float evasionSpeedModifier;
int evasionRange;
bool evade = false;
public EvadingSprite(Texture2D textureImage, Vector2 position,
Point frameSize, int collisionOffset, Point currentFrame,
Point sheetSize, Vector2 speed, string collisionCueName,
SpriteManager spriteManager, float evasionSpeedModifier,
int evasionRange)
: base(textureImage, position, frameSize, collisionOffset,
currentFrame, sheetSize, speed, collisionCueName)
{
this.spriteManager = spriteManager;
this.evasionSpeedModifier = evasionSpeedModifier;
this.evasionRange = evasionRange;
}
public EvadingSprite(Texture2D textureImage, Vector2 position,
Point frameSize, int collisionOffset, Point currentFrame,
Point sheetSize, Vector2 speed, int millisecondsPerFrame,
string collisionCueName, SpriteManager spriteManager,
float evasionSpeedModifier, int evasionRange)
: base(textureImage, position, frameSize, collisionOffset,
currentFrame, sheetSize, speed, millisecondsPerFrame,
collisionCueName)
{
this.spriteManager = spriteManager;
this.evasionSpeedModifier = evasionSpeedModifier;
this.evasionRange = evasionRange;
}
public override Vector2 direction
{
get { return speed; }
}
public override void Update(GameTime gameTime, Rectangle clientBounds)
{
// First, move the sprite along its direction vector
position += speed;
// Use the player position to move the sprite closer in
// the X and/or Y directions
Vector2 player = spriteManager.GetPlayerPosition();
if (evade)
{
// Move away from the player horizontally
if (player.X < position.Y)
position.X += Math.Abs(speed.Y);
else if (player.X > position.X)
position.X -= Math.Abs(speed.Y);
// Move away from the player vertically
if (player.Y < position.Y)
position.Y += Math.Abs(speed.X);
else if (player.Y > position.Y)
position.Y -= Math.Abs(speed.X);
}
else
{
if (Vector2.Distance(position, player) < evasionRange)
{
// Player is within evasion range,
// reverse direction and modify speed
speed *= -evasionSpeedModifier;
evade = true;
}
}
//make them bounce off walls
if (position.X > clientBounds.Width - frameSize.X ||
position.X < 0)
speed *= -1;
if (position.Y > clientBounds.Height - frameSize.Y ||
position.Y < 0)
speed *= -1;
base.Update(gameTime, clientBounds);
}
}
For your collision code:
if (position.Y > clientBounds.Height - frameSize.Y ||
position.Y < 0)
speed *= -1;
You are telling the sprite to go only go up. Basically when it hits -1 on the y its moving in the positive direction until it goes positive in which case its moving negative. So you keep switching between positive and negative off screen. My recommendation would be to split those statements up into two, that way when your not evading you are accurately bouncing off the walls.
if (position.X > clientBounds.Width - frameSize.X)
speed *= -1;
else if (position.X<=0)
speed*=1;
if (position.Y > ClientBounds.Height - frameSize.Y)
speed *= -1;
else if(position.Y > 0)
speed *= 1;