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;
Related
I am drawing two wireframe spheres that I would like to follow the player around. When the player moves the two gizmos follow, however, when I rotate only one of the gizmos rotates.
The broken gizmo code looks like this, it should have an offset of 45:
void OnDrawGizmosSelected() {
Gizmos.color = new Color(1, 0, 0);
Gizmos.matrix = Matrix4x4.TRS(transform.position, Quaternion.Euler(transform.rotation.x, transform.rotation.y + 45, transform.rotation.z), Vector3.one);
Gizmos.DrawWireSphere(Vector3.zero, 5f);
}
For reference here is the whole block with both gizmos:
void OnDrawGizmosSelected() {
Gizmos.color = new Color(1, 0, 0);
// This one works
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
Gizmos.DrawWireSphere(Vector3.zero, 5f);
// This one does not work
Gizmos.matrix = Matrix4x4.TRS(transform.position, Quaternion.Euler(transform.rotation.x, transform.rotation.y + 45, transform.rotation.z), Vector3.one);
Gizmos.DrawWireSphere(Vector3.zero, 5f);
}
Default with no rotation (How I want it to stay when rotating)
Rotation around the Y Axis
Quaternion has 4 components, x,y,z and w.
Just putting x,y and z into Quaternion.Euler will not give you the expected results.
Instead, use transform.rotation.eulerAngles
void OnDrawGizmosSelected()
{
Gizmos.color = new Color(1, 0, 0);
// This one works
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
Gizmos.DrawWireSphere(Vector3.zero, 5f);
// This one works now :)
Gizmos.matrix = Matrix4x4.TRS(transform.position, Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + 45, transform.rotation.eulerAngles.z), Vector3.one);
Gizmos.DrawWireSphere(Vector3.zero, 5f);
}
EDIT:
Okay, that fixes the Y value, but X and Z are still broken. They move but not in the proper direction.
Then try
// This works even better
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one) * Matrix4x4.Rotate(Quaternion.Euler(0, 45, 0));
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 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
When I create particle effects, they all have the same pattern. They are rotated, but they all have the same pattern and same colored particles. See picture:
This is how a new ParticleEffect gets created:
ParticleEffect p = new ParticleEffect(textures, Vector2.Zero, destination, speed);
Where textures is aTexture2D list, VectorZero is the starting location, and so on.
Whenever a new ParticleEffect gets created it gets added to the ParticleList list, which later loops through all the items and calls update and draw for each effect inside.
Here is where the particles are randomised:
private Particle GenerateNewParticle()
{
Random random = new Random();
Texture2D texture = textures[random.Next(textures.Count)];
Vector2 position = EmitterLocation;
Vector2 velocity = new Vector2(
1f * (float)(random.NextDouble() * 2 - 1),
1f * (float)(random.NextDouble() * 2 - 1));
float angle = 0;
float angularVelocity = 0.1f * (float)(random.NextDouble() * 2 - 1);
Color color = new Color(
(float)random.NextDouble(),
(float)random.NextDouble(),
(float)random.NextDouble());
float size = (float)random.NextDouble();
int ttl = 20 + random.Next(40);
return new Particle(texture, position, velocity, angle, angularVelocity, color, size, ttl);
}
A bunch of randoms there, but each effect still comes out the same.
Comment if you want to see more code.
Edit:
Here is how a particle gets drawn:
public void Draw(SpriteBatch spriteBatch)
{
Rectangle sourceRectangle = new Rectangle(0, 0, Texture.Width, Texture.Height);
Vector2 origin = new Vector2(Texture.Width / 2, Texture.Height / 2);
spriteBatch.Draw(Texture, Position, sourceRectangle, Color,
Angle, origin, Size, SpriteEffects.None, 0f);
}
By default, Random instances are initiated with the current time as seed, that means the same sequence of numbers will be re-generated if you create instances at the same time - do not create new instances, reuse an existing instance to get more "randomized" behavior (in your case e.g. use a static Random instance).
Ok guys, this one is literally killing my mind, as I've been able to render models just fine
(in fact I had to in order to test out my camera).
However now that I'm trying to draw a cube from a vertex and index buffer, it just won't work.
(I've been able to draw triangles and such, but never from their own class).
My end goal is to be able to build regions of 64x64x8 cubes to create the game world.
(Not a minecraft clone, actually an RTS -- it'll have a "2d" feel in that the game world itself will only ever be 8 cubes deep, but I digress).
From looking over the various index & vertex tutorials all over the web, it looks to me like this should work. Here's some code.....
game.cs
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
float timeDifference = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
cam.Update(timeDifference);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
cube = new CubeShape(Color.Black, new Vector3(0, 0, 0), GraphicsDevice);
RasterizerState rasterizerState = new RasterizerState();
rasterizerState.CullMode = CullMode.None;
GraphicsDevice.RasterizerState = rasterizerState;
cube.Render(cam.viewMatrix,cam.projectionMatrix);
base.Draw(gameTime);
}
}
and my cube (this one is kind of long, sorry)
class CubeShape
{
//Transform later to have static v and i buffers.
private VertexBuffer vBuffer;
public VertexBuffer VBuffer
{ get { return vBuffer; } set { vBuffer = value; } }
private IndexBuffer iBuffer;
public IndexBuffer IBuffer
{ get { return iBuffer; } set { iBuffer = value; } }
private BasicEffect bEffect;
public BasicEffect BEffect
{ get { return bEffect; } set { bEffect = value; } }
private Matrix world;
public Matrix World
{ get { return world; } set { world = value; } }
private Matrix view;
public Matrix View
{ get { return view; } set { view = value; } }
private Matrix projection;
private Matrix Projection
{ get { return projection; } set { projection = value; } }
private Color color;
public Color Color
{ get { return color; } set { color = value; } }
private Vector3 position;
public Vector3 Position
{ get { return position; } set { position = value; } }
//Need to change this eventually to use textures.
private VertexPositionColor[] vertices;
byte[] indices;
private GraphicsDevice device;
//constructors!
public CubeShape(Color inColor,Vector3 inPosition,GraphicsDevice inDevice)
{
device = inDevice;
this.color = inColor;
this.position = inPosition;
SetUpVertices();
SetUpIndices();
//world = Matrix.CreateTranslation(position);
world = Matrix.CreateTranslation(0, 0, 0);
bEffect = new BasicEffect(device);
bEffect.World = world;
bEffect.VertexColorEnabled = true;
}
//end constructors!
// >.<
public void Render(Matrix view,Matrix projection)
{
bEffect.View = view;
bEffect.Projection = projection;
device.SetVertexBuffer(vBuffer);
device.Indices = IBuffer;
foreach(EffectPass pass in bEffect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 12);
}
}
/// <summary>
/// Sets up the vertices for a cube using 8 unique vertices.
/// Build order is front to back, left to up to right to down.
/// </summary>
private void SetUpVertices()
{
vertices = new VertexPositionColor[8];
//front left bottom corner
vertices[0] = new VertexPositionColor(new Vector3(0, 0, 0), color);
//front left upper corner
vertices[1] = new VertexPositionColor(new Vector3(0, 100, 0), color);
//front right upper corner
vertices[2] = new VertexPositionColor(new Vector3(100, 100, 0), color);
//front lower right corner
vertices[3] = new VertexPositionColor(new Vector3(100, 0, 0), color);
//back left lower corner
vertices[4] = new VertexPositionColor(new Vector3(0, 0, -100), color);
//back left upper corner
vertices[5] = new VertexPositionColor(new Vector3(0, 100, -100), color);
//back right upper corner
vertices[6] = new VertexPositionColor(new Vector3(100, 100, -100), color);
//back right lower corner
vertices[7] = new VertexPositionColor(new Vector3(100, 0, -100), color);
vBuffer = new VertexBuffer(device, typeof(VertexPositionColor), 8, BufferUsage.WriteOnly);
vBuffer.SetData<VertexPositionColor>(vertices);
}
/// <summary>
/// Sets up the indices for a cube. Has 36 positions that match up
/// to the element numbers of the vertices created earlier.
/// Valid range is 0-7 for each value.
/// </summary>
private void SetUpIndices()
{
indices = new byte[36];
//Front face
//bottom right triangle
indices[0] = 0;
indices[1] = 3;
indices[2] = 2;
//top left triangle
indices[3] = 2;
indices[4] = 1;
indices[5] = 0;
//back face
//bottom right triangle
indices[6] = 4;
indices[7] = 7;
indices[8] = 6;
//top left triangle
indices[9] = 6;
indices[10] = 5;
indices[11] = 4;
//Top face
//bottom right triangle
indices[12] = 1;
indices[13] = 2;
indices[14] = 6;
//top left triangle
indices[15] = 6;
indices[16] = 5;
indices[17] = 1;
//bottom face
//bottom right triangle
indices[18] = 4;
indices[19] = 7;
indices[20] = 3;
//top left triangle
indices[21] = 3;
indices[22] = 0;
indices[23] = 4;
//left face
//bottom right triangle
indices[24] = 4;
indices[25] = 0;
indices[26] = 1;
//top left triangle
indices[27] = 1;
indices[28] = 5;
indices[29] = 4;
//right face
//bottom right triangle
indices[30] = 3;
indices[31] = 7;
indices[32] = 6;
//top left triangle
indices[33] = 6;
indices[34] = 2;
indices[35] = 3;
iBuffer = new IndexBuffer(device, typeof(short), 36, BufferUsage.WriteOnly);
iBuffer.SetData(indices);
}
}
I really have no clue why this isn't working. Probably because I've been having a staredown with the code for the last 4 hours >.<
Oh, the camera starts at 0,0,50 and is facing 0,0,0. It also allows me to move around with the mouse and keyboard (like any rts cam should) with rotation (middle mouse button held down). I've searched all around just to make sure my cube wasn't somewhere outside of my view range,but all I see is blue >.<
I'd appreciate any help here.
p.s. as a secondary question, any hints on how to share buffers between cubes?
I read that since the geometry of a cube never changes, that it's more efficient to share buffers but I'm not sure how to go about this...create one decently big buffer and fill it with cubes from some kind of list class that holds all the cubes that need to be rendered maybe? not even sure where to start looking. Again, thanks much for any input/advice.
It looks like you have some typing issues. I got it to work by changing the following code:
//byte[] indices;
short[] indices;
//indices = new byte[36];
indices = new short[36];
//iBuffer = new IndexBuffer(device, typeof(short), 36, BufferUsage.WriteOnly);
iBuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, sizeof(short) * indices.Length, BufferUsage.WriteOnly);
If it still does not work, yell at me and I will check to make sure that I did not miss anything. Keep in mind, I had to use one of my own camera classes since you did not include yours.
I am not sure how to answer your second question. You might want to ask it as a separate question.