How to move the ball in different directions? - c#
Now when I hit spacebar it will go left or right, I want the ball to go straight first time.Then when the ball hit a wall, block or line after that I want the ball to go random directions with "-1" somehow. This is my first school game project, it's a one line pong game.
Edit: Edit I've added "boll_speed.X = random.Next(-1, 1);", and that works perfectly!
linje = line
liv = lives
boll = ball
poang = points
I don't use "blockröd = blockred" right now
blockgrön = blockgreen
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont spritefont;
Texture2D linje_texture;
Texture2D boll_texture;
Texture2D blockröd_texture;
Texture2D blockgrön_texture;
Texture2D gameover_texture;
Rectangle linje_rect;
Rectangle boll_rect;
Rectangle blockröd_rect;
Rectangle blockgrön_rect;
Rectangle gameover_rect;
Vector2 linje_speed;
Vector2 boll_speed;
Random random;
int liv;
int poang;
int highscore;
List<Rectangle> block = new List<Rectangle>();
bool Start = false;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 760;
graphics.PreferredBackBufferHeight = 620;
}
protected override void Initialize()
{
linje_speed.X = 5f;
boll_speed.X = boll_speed.X = random.Next(-1, 1);
boll_speed.Y = 6f;
liv = 3;
poang = 0;
random = new Random();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spritefont = Content.Load<SpriteFont>("Fonts/Myfont");
linje_texture = Content.Load<Texture2D>("Pics/linje-lång");
boll_texture = Content.Load<Texture2D>("Pics/boll");
blockgrön_texture = Content.Load<Texture2D>("Pics/block-grön");
blockröd_texture = Content.Load<Texture2D>("Pics/block-röd");
gameover_texture = Content.Load<Texture2D>("Pics/GameOver");
linje_rect = new Rectangle((Window.ClientBounds.Width - linje_texture.Width) / 2, 580, linje_texture.Width, linje_texture.Height);
boll_rect = new Rectangle((Window.ClientBounds.Width - boll_texture.Width) / 2, 556, boll_texture.Width, boll_texture.Height);
gameover_rect = new Rectangle((Window.ClientBounds.Width / 2) - (gameover_texture.Width / 2), (Window.ClientBounds.Height / 2) - gameover_texture.Height / 2, gameover_texture.Width, gameover_texture.Height);
block.Add(blockgrön_rect);
block.Add(blockröd_rect);
for (int i = 1; i < 5; i++)
{
for (int g = 1; g < 13; g++)
{
block.Add(new Rectangle((g * 63) - 60, (i * 40), blockgrön_texture.Width, blockgrön_texture.Height));
}
}
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Start == true)
{
boll_rect.X += (int)boll_speed.X;
boll_rect.Y += (int)boll_speed.Y;
}
if(Start == false)
{
boll_rect.X = linje_rect.X + ((linje_texture.Width / 2) - (boll_texture.Width / 2));
}
if (boll_rect.X > Window.ClientBounds.Width - boll_texture.Width || boll_rect.X < 0)
boll_speed.X *= -1;
if (boll_rect.Y > Window.ClientBounds.Height - boll_texture.Height || boll_rect.Y < 0)
boll_speed.Y *= -1;
if (boll_rect.Y > Window.ClientBounds.Height - boll_texture.Height)
{
liv -= 1;
Start = false;
boll_rect.X = (Window.ClientBounds.Width - boll_texture.Width) / 2;
boll_rect.Y = 556;
linje_rect.X = (Window.ClientBounds.Width - linje_texture.Width) / 2;
linje_rect.Y = 580;
}
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Left))
{
linje_rect.X -= (int)linje_speed.X;
}
else if (ks.IsKeyDown(Keys.Right))
{
linje_rect.X += (int)linje_speed.X;
}
else if (ks.IsKeyDown(Keys.Space))
{
Start = true;
}
if (linje_rect.X > Window.ClientBounds.Width - linje_texture.Width)
linje_rect.X = (Window.ClientBounds.Width - linje_texture.Width);
if (linje_rect.X < 0)
linje_rect.X = 0;
if (linje_rect.Intersects(boll_rect))
{
boll_speed.Y *= -1;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
if (liv > 0)
{
spriteBatch.Draw(linje_texture, linje_rect, Color.White);
spriteBatch.Draw(boll_texture, boll_rect, Color.White);
spriteBatch.DrawString(spritefont, "Liv kvar: " + liv, Vector2.Zero, Color.White);
spriteBatch.DrawString(spritefont, "Points: " + poang, new Vector2(350, 0), Color.White);
spriteBatch.DrawString(spritefont, "Highscore: " + highscore, new Vector2(660, 0), Color.White);
foreach (Rectangle g in block)
{
spriteBatch.Draw(blockgrön_texture, g, Color.White);
}
}
if (liv == 0)
{
spriteBatch.Draw(gameover_texture, gameover_rect, Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Having trouble with these parts:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Start == true)
{
boll_rect.X += (int)boll_speed.X;
boll_rect.Y += (int)boll_speed.Y;
}
if (boll_rect.X > Window.ClientBounds.Width - boll_texture.Width || boll_rect.X < 0)
boll_speed.X *= -1;
if (boll_rect.Y > Window.ClientBounds.Height - boll_texture.Height || boll_rect.Y < 0)
boll_speed.Y *= -1;
else if (ks.IsKeyDown(Keys.Space))
{
Start = true;
}
if (linje_rect.Intersects(boll_rect))
{
boll_speed.Y *= -1;
boll_speed.Y += random.Next(-100, 101) / 100.0f;
boll_speed.X *= -1;
boll_speed.X += random.Next(-100, 101) / 100.0f;
}
I will give you the generic idea. Please adapt it to your example
Lets say you want to move to all directions on the board, now imagine your board as a bi-dimensional array(all your pixels has an x,y representation on that board)
The (0,0) marks the left upper corner of your board, and your (width, height) mark the lower right corner. Your ball is on the middle of the board on the (x, y) position, where x > 0 and x < width(of the board) and y > 0 and y < height.
You have 8 different directions base on the picture below
Now it is time to translate those directions to a logical structure. You need to create an array for that, lets say we want to start from the NW direction. I will create an array with the numbers that you need to add to your (x, y) position in order to keep going in the direction you choose. If you see I am creating a bidimentional array
Now this is the pseudocode for your idea:
int[,] directions = new int[,]{{-1,-1,-1,0,1,1,1,0}, {-1,0,1,1,1,0,-1,-1}};
public void Move(Game game)
{
Point currentPosition = GetYourCurrentPosition(); //the x, y
int direction = GetYourRandomDirection() //this should be a random number between 0 and 7, beucase the array for directions has 8 positions.
int xDirection = directions[0, direction];
int yDirection = directions[1, direction];
//move inside the board forever
while(true)
{
while(ICanMoveTo(currentPosition.X + xDirection, currentPosition.Y + yDirection)
{
//keep moving on the same direction
currentPosition.X += xDirection;
currentPosition.Y += yDirection;
}
//if you can't move anymore in the same direction, then change
direction = GetYourRandomDirection();
xDirection = directions[0, direction];
yDirection = directions[1, direction];
}
}
Random.Next(-1) should give you out of bounds error.
You can use something like Random.Next(-200, 0)/100.0f, which will return a negative number between -2 and 0 (including -2, excluding 0).
But notice that this multiplication will lead to slowdown of ball over time. It might speed up to double of current speed, but it can slow down to nearly 0 in a single step. So I would rather first invert ball speed in y direction and keep it the same in x if you hit horizontal lines, and invert in x and keep in y if you hit vertical lines. Then do a random addition of a zero-means constant.
boll_speed.Y *= -1;
boll_speed.Y += random.Next(-100, 101)/100.0f; // Add random number between -1 and 1 with 0.01 precision.
// and nearly the same for X. Depending on the lines hit.
I'm thinking you mean you want the ball to change directions randomly when it hits the window boundaries or line. If so:
You're using constant values for your direction changes. Add a randomizer to multiply your boll_speed by.
For example, in pseudocode, instead of -1, do random(-1).
Related
Trying to add new levels to my Breakout game
I have a problem with my code, check the code down below, so you understand which section i'm talking about! I'm trying to add new block levels when "block.Count == 1", you know when all my blocks are destroyed by the ball. I want it to start a new level with a different block path. When I have: else if (block.Count == 1 && block2.Count == 1) { spriteBatch.Draw(gameover_texture, gameover_rect, Color.White); } It doesn't draw out my gameover_texture, when are blocks are gone? (Sorry about my bad english) public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont spritefont; Texture2D paddle_texture; Texture2D ball_texture; Texture2D blockred_texture; Texture2D blockgreen_texture; Texture2D gameover_texture; Rectangle paddle_rect; Rectangle ball_rect; Rectangle blockred_rect; Rectangle blockgreen_rect; Rectangle gameover_rect; Vector2 paddle_speed; Vector2 ball_speed; Random random; StreamReader sr; StreamWriter sw; int lives = 3; int points = 0; int highscore; int counter = 0; int seconds = 0; List<Rectangle> block = new List<Rectangle>(); List<Rectangle> block2 = new List<Rectangle>(); bool Start = false; bool holdingleft = false; bool holdingright = false; bool resetballspeed = false; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferWidth = 760; graphics.PreferredBackBufferHeight = 620; } protected override void Initialize() { random = new Random(); paddle_speed.X = 6f; ball_speed.X = random.Next(-1, 1); ball_speed.Y = 7f; sr = new StreamReader("highscore.txt"); highscore = int.Parse(sr.ReadLine()); sr.Close(); base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); spritefont = Content.Load<SpriteFont>("Fonts/Myfont"); paddle_texture = Content.Load<Texture2D>("Pics/linje"); ball_texture = Content.Load<Texture2D>("Pics/boll"); blockgreen_texture = Content.Load<Texture2D>("Pics/block-grön"); blockred_texture = Content.Load<Texture2D>("Pics/block-röd"); gameover_texture = Content.Load<Texture2D>("Pics/GameOver"); paddle_rect = new Rectangle((Window.ClientBounds.Width - paddle_texture.Width) / 2, 580, paddle_texture.Width, paddle_texture.Height); ball_rect = new Rectangle((Window.ClientBounds.Width - ball_texture.Width) / 2, 556, ball_texture.Width, ball_texture.Height); gameover_rect = new Rectangle((Window.ClientBounds.Width / 2) - (gameover_texture.Width / 2), (Window.ClientBounds.Height / 2) - gameover_texture.Height / 2, gameover_texture.Width, gameover_texture.Height); block.Add(blockgreen_rect); block2.Add(blockred_rect); for (int i = 1; i < 2; i++) { for (int g = 1; g < 3; g++) { block2.Add(new Rectangle((g * 63) - 60, (i * 40), blockred_texture.Width, blockred_texture.Height)); } } for (int i = 1; i < 2; i++) { for (int g = 1; g < 3; g++) { block.Add(new Rectangle((g * 63) - 60, (i * 20) + 40, blockgreen_texture.Width, blockgreen_texture.Height)); } } } protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); if (Start == true) //kolla om "Start == true", { ball_rect.X += (int)ball_speed.X; ball_rect.Y += (int)ball_speed.Y; } if (Start == false) { ball_rect.X = paddle_rect.X + ((paddle_rect.Width / 2) - (ball_texture.Width / 2)); } if (ball_rect.X > Window.ClientBounds.Width - ball_texture.Width || ball_rect.X < 0) ball_speed.X *= -1; if (ball_rect.Y > Window.ClientBounds.Height - ball_texture.Height || ball_rect.Y < 0) ball_speed.Y *= -1; if (ball_rect.Y > Window.ClientBounds.Height - ball_texture.Height) { lives -= 1; Start = false; ball_rect.X = (Window.ClientBounds.Width - ball_texture.Width) / 2; ball_rect.Y = 556; paddle_rect.X = (Window.ClientBounds.Width - paddle_texture.Width) / 2; paddle_rect.Y = 580; } KeyboardState ks = Keyboard.GetState(); if (ks.IsKeyDown(Keys.Left)) { paddle_rect.X -= (int)paddle_speed.X; holdingleft = true; } else if (ks.IsKeyDown(Keys.Right)) { paddle_rect.X += (int)paddle_speed.X; holdingright = true; } else if (ks.IsKeyDown(Keys.Space)) { Start = true; } else if (ks.Equals(new KeyboardState())) { resetballspeed = true; } if (paddle_rect.X > Window.ClientBounds.Width - paddle_rect.Width) paddle_rect.X = (Window.ClientBounds.Width - paddle_rect.Width); if (paddle_rect.X < 0) paddle_rect.X = 0; if (paddle_rect.Intersects(ball_rect)) { ball_speed.Y *= -1; ball_rect.Y += (int)ball_speed.Y; if (holdingleft == true) { ball_speed.X -= 3; } else if (holdingright == true) { ball_speed.X += 3; } else if (resetballspeed == true) { ball_speed.X = 1; } } if (points == highscore) { sw = new StreamWriter("highscore.txt"); sw.WriteLine(points); sw.Close(); } for (int j = 1; j < block.Count; j++) { if (ball_rect.Intersects(block[j])) { ball_speed.Y *= -1; points += 1; block.RemoveAt(j); if (points > 9) { paddle_rect.Width = 60; } if (points > highscore) { highscore = points; } } } for (int k = 1; k < block2.Count; k++) { if (ball_rect.Intersects(block2[k])) { ball_speed.Y *= -1; points += 5; block2.RemoveAt(k); if (points > 9) { paddle_rect.Width = 60; } if (points > highscore) { highscore = points; } } } holdingleft = false; holdingright = false; counter++; if (counter == 60) { seconds++; counter = 0; } base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.Black); // TODO: Add your drawing code here spriteBatch.Begin(); if (lives > 0) { spriteBatch.Draw(ball_texture, ball_rect, Color.White); spriteBatch.Draw(paddle_texture, paddle_rect, Color.White); spriteBatch.DrawString(spritefont, "Lives left: " + lives, Vector2.Zero, Color.White); spriteBatch.DrawString(spritefont, "Points: " + points, new Vector2(350, 0), Color.White); spriteBatch.DrawString(spritefont, "Timer: " + seconds, new Vector2(350, 600), Color.White); spriteBatch.DrawString(spritefont, "Highscore: " + highscore, new Vector2(660, 0), Color.White); foreach (Rectangle g in block) { spriteBatch.Draw(blockgreen_texture, g, Color.White); } foreach (Rectangle t in block2) { spriteBatch.Draw(blockred_texture, t, Color.White); } } else if (block.Count == 1 && block2.Count == 1) { spriteBatch.Draw(gameover_texture, gameover_rect, Color.White); } else if (lives == 0) { spriteBatch.Draw(gameover_texture, gameover_rect, Color.White); } spriteBatch.End(); base.Draw(gameTime); } }
Fixed the problem now, by putting the else if-statement inside "if (lives > 0)"
XNA Loading Models
I am pretty new to the 3D side of XNA and am converting a 2D game. Its basically designed as a grid and I am drawing with the code below. This works but is a bit laggy, am I doing this completely wrong? Presumably there shouldn't be much lag at this point when we are only talking about a few small models. protected override void Draw(GameTime gameTime) { fpsTimer += gameTime.ElapsedGameTime; fpsCount++; if (fpsTimer >= TimeSpan.FromSeconds(1)) { fpsTimer = TimeSpan.FromSeconds(0); fps = fpsCount; fpsCount = 0; } GraphicsDevice.Clear(Color.CornflowerBlue); projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, 1000.0f); world = Matrix.CreateTranslation(new Vector3(0, 0, 0)); view = Matrix.CreateLookAt(new Vector3(xPos, yPos, zHeight), new Vector3(xPos, yPos + zRotation, 0), new Vector3(0, 5, 0)); // DRAW OBJECTS ON MAP drawMap(view, world, projection); spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); spriteBatch.DrawString(font, "" + fps, new Vector2(100, 100), Color.Black); spriteBatch.End(); base.Draw(gameTime); } private void drawMap(Matrix view, Matrix world, Matrix projection) { GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap; int scale = Globals.scale; int screenWidthScale = Globals.screenwidth / scale; int screenHeightScale = Globals.screenheight / scale; int mapXtile = Convert.ToInt32(xPos/2); int mapYtile = Convert.ToInt32(yPos/2); for (int i = Convert.ToInt32(xPos/2) - 30; i < Convert.ToInt32(xPos/2) + 30; i++) { for (int a = Convert.ToInt32(yPos/2); a < Convert.ToInt32(yPos/2) + 50; a++) { if (mapXtile > 0 && mapYtile > 0 && mapXtile < Globals.mapsizex && mapYtile < Globals.mapsizey) { int currentTile = Globals.levelArray[mapXtile, mapYtile].TyleType; // DRAW TREES if (currentTile == tyleType.tree) { if (Globals.levelArray[mapXtile, mapYtile].typeModifier == 1) { Matrix worldMatrix = Matrix.CreateScale(0.8f, 0.8f, 0.8f) * Matrix.CreateRotationX(1.5f) * Matrix.CreateTranslation(new Vector3(i * 2 + 0.2f, a * 2 - 0.4f, -0.1f)); tree.Draw(worldMatrix, view, projection); } if (Globals.levelArray[mapXtile, mapYtile].typeModifier == 2) { Matrix worldMatrix = Matrix.CreateScale(0.8f, 0.8f, 0.8f) * Matrix.CreateRotationX(1.5f) * Matrix.CreateTranslation(new Vector3(i * 2+0.2f, a * 2-0.4f, -0.1f)); tree2.Draw(worldMatrix, view, projection); } } } mapYtile = mapYtile + 1; //mapYtile++; } mapXtile = mapXtile + 1; mapYtile = Convert.ToInt32(yPos / 2); } }
Tile System with moving Platforms
Using a tile based system I need to separate platform block from the rest and then allow them to move up and down at a constant speed. How would I make the tile that is labeled '=' (Vertical Moving Platform) to move up or down until it hits either a '#' (Wall) or an end point '+' (Vertical Moving Platform Movement Area)? There is a camera class that follows the player, a player class that controls the movement and a Block class that controls the collision of blocks. List were the blocks are stored: List<Block> Blocks; List were the levels are stored: List<char[,]> Levels = new List<char[,]>(); Here is where the levels are created(Test Map): protected override void Initialize() { Blocks = new List<Block>(); char[,] Level2 = {{'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, {'.','.','.','.','.','.','.','.','.','.','.','.','.','.','+','.'}, {'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, {'.','.','.','.','.','.','.','.','.','.','.','.','#','.','.','.'}, {'.','.','.','.','.','.','.','-','-','-','.','.','#','.','.','.'}, {'.','.','.','.','.','.','.','.','.','.','.','.','#','.','.','.'}, {'.','.','.','-','-','-','.','.','.','.','.','.','#','.','.','.'}, {'.','.','.','.','.','.','.','.','.','.','.','.','#','.','.','.'}, {'#','#','.','.','.','.','.','.','.','P','.','.','#','.','=','.'}, {'#','#','#','#','#','#','#','#','#','#','#','#','#','#','#','#'}}; Levels.Add(Level2); base.Initialize(); } Here is the void LoadLevel that will give meaning the to level(This is called when the player completes the level and in the LoadContent Method): void LoadLevel(int level) { Blocks.Clear(); player.Position = Vector2.Zero; tileWidth = Levels[level].GetLength(1); tileHeight = Levels[level].GetLength(0); for (int x = 0; x < tileWidth; x++) { for (int y = 0; y < tileHeight; y++) { //Background Blocks.Add(new Block(background, new Vector2(x * 50, y * 50), 0)); //Impassable Blocks if (Levels[level][y, x] == '#') { Blocks.Add(new Block(blockSpriteA, new Vector2(x * 50, y * 50), 1)); } //Blocks that are only passable if going up them if (Levels[level][y, x] == '-') { Blocks.Add(new Block(blockSpriteB, new Vector2(x * 50, y * 50), 2)); } //Vertical Moving Platform Movement Area if (Levels[level][y, x] == '+') { Blocks.Add(new Block(movingArea, new Vector2(x * 50, y * 50), 3)); } //Vertical Moving Platform if (Levels[level][y, x] == '=') { Blocks.Add(new Block(movingPlatform, new Vector2((x * 50), (y * 50) + movingPlatform.Height), 4)); } //PlayerSpawn if (Levels[level][y, x] == 'P' && player.Position == Vector2.Zero) { player.Position = new Vector2(x * 50, (y + 1) * 50 - player.Texture.Height); player.Velocity = new Vector2(0, 0); player.initialVelocity = 0; player.Time = 0; player.isJumping = false; } else if (Levels[level][y, x] == 'P' && player.Position != Vector2.Zero) { throw new Exception("Only one 'P' is needed for each level"); } } } if (player.Position == Vector2.Zero) { throw new Exception("Player Position needs to be set with 'P'"); } } Update Method: 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 HandleInput(Keyboard.GetState()); player.Update(gameTime); Time += (float)gameTime.ElapsedGameTime.TotalSeconds; foreach (Block b in Blocks) { player = b.BlockCollision(player); } camera.thing(player); prevKB = Keyboard.GetState(); base.Update(gameTime); } Draw Method: protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.White); // TODO: Add your drawing code here spriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, null, null, null, null, camera.Transform()); //spriteBatch.Begin(); foreach (Block b in Blocks) { b.Draw(spriteBatch); } spriteBatch.End(); base.Draw(gameTime); }
Make a class like Block( something like MovingBlock ) Add an update method in the class so the block moves up and down. Use the class in your LoadLevel if (Levels[level][y, x] == '=') { MovingBlocks.Add(new MovingBlock(movingPlatform, new Vector2((x * 50), (y * 50) + movingPlatform.Height) , 4)); }
Unity3d render texture based on position
I'm currently trying to create a container in Unity with multiple quads inside, and am looking for a way to stop parts of the quad that fall outside of the containers bounds from being rendered? I just spent twenty minutes trying to fiqure out how to explain the problem properly (and failed) so created this pretty picture instead. The red line represents the bounds with the black squares representing my textured quads.
Try this: private Rect ClipRectToScreen (Rect input) { // Special handling for screen reading of render texture so it always stay in visible area. // Will throw error withoud this fix. Rect r; r = new Rect (input.x, (Screen.height - input.y - input.height) , input.width, input.height); if (r.x < 0f) { r.width = r.width - UnityEngine.Mathf.Abs (r.x); r.x = 0f; // Debug.Log ("x < 0"); } if (r.y < 0f) { r.height = r.height - UnityEngine.Mathf.Abs (r.y); r.y = 0f; // Debug.Log ("y < 0"); } if (r.x > Screen.width) { r.width = r.width - UnityEngine.Mathf.Abs (r.x); r.x = 0f; // Debug.Log ("x > Screen.width"); } if (r.y > Screen.height) { r.height = r.height - UnityEngine.Mathf.Abs (r.y); r.y = 0f; // Debug.Log ("y > Screen.height"); } if ((r.x + r.width) > Screen.width) { r.width = Screen.width - r.x; // Debug.Log ("r.x + r.width > Screen.width"); } if ((r.y + r.height) > Screen.height) { r.height = Screen.height - r.y; // Debug.Log ("r.y + r.height > Screen.height"); } return r; }
Optimizing a formula to create a triangle from arbitrary points
I think a little background will help before I get into my question. What I'm doing is creating my own small 2D physics library in xna, for fun nonetheless. This is also my first independent xna project, and my first time working with the 3D tools, so I may be doing things all wacky. Anyway, I'm currently making a triangle class in which the constructor takes three arbitrary points in the form of Vector2s. In the constructor I have to put these points in clockwise order (so they're not culled) and then find the texture coordinates they should correspond to (since I'm using VertexPositionTextures as my vertices). What I've got works, but it seems very long and complicated. I'm looking for any ways to shorten/simplify the code, which is this: public PTriangle(Vector2 a, Vector2 b, Vector2 c) : base() { //set up vertices VertexPositionTexture[] vertices = new VertexPositionTexture[3]; //center vertices around origin Vector2 center = new Vector2((a.X + b.X + c.X) / 3, (a.Y + b.Y + c.Y) / 3); Vector2 newA = a - center; Vector2 newB = b - center; Vector2 newC = c - center; //get angle of each vertex (clockwise from -x axis) double angleA = MathHelper.Pi - Math.Atan((double)(newA.Y / newA.X)); double angleB = MathHelper.Pi - Math.Atan((double)(newB.Y / newB.X)); double angleC = MathHelper.Pi - Math.Atan((double)(newC.Y / newC.X)); if (newA.X < 0) { if (newA.Y < 0) { angleA += MathHelper.Pi; } else { angleA -= MathHelper.Pi; } } if (newB.X < 0) { if (newB.Y < 0) { angleB += MathHelper.Pi; } else { angleB -= MathHelper.Pi; } } if (newC.X < 0) { if (newC.Y < 0) { angleC += MathHelper.Pi; } else { angleC -= MathHelper.Pi; } } //order vertices by angle Vector2[] newVertices = new Vector2[3]; if (angleA < angleB && angleA < angleC) { newVertices[0] = newA; if (angleB < angleC) { newVertices[1] = newB; newVertices[2] = newC; } else { newVertices[1] = newC; newVertices[2] = newB; } } else if (angleB < angleA && angleB < angleC) { newVertices[0] = newB; if (angleA < angleC) { newVertices[1] = newA; newVertices[2] = newC; } else { newVertices[1] = newC; newVertices[2] = newA; } } else { newVertices[0] = newC; if (angleA < angleB) { newVertices[1] = newA; newVertices[2] = newB; } else { newVertices[1] = newB; newVertices[2] = newA; } } //set positions of vertices vertices[0].Position = new Vector3(newVertices[0] + center, 0); vertices[1].Position = new Vector3(newVertices[1] + center, 0); vertices[2].Position = new Vector3(newVertices[2] + center, 0); //get width and height of triangle float minX = 0; float minY = 0; float maxX = 0; float maxY = 0; foreach (Vector2 vertex in newVertices) { if (vertex.X < minX) { minX = vertex.X; } else if (vertex.X > maxX) { maxX = vertex.X; } if (vertex.Y < minY) { minY = vertex.Y; } else if (vertex.Y > maxY) { maxY = vertex.Y; } } float width = maxX - minX; float height = maxY - minY; //shift triangle so fits in quadrant IV, and set texture coordinates for (int index = 0; index < newVertices.Length; ++index) { newVertices[index].X -= minX; newVertices[index].Y -= minY; vertices[index].TextureCoordinate = new Vector2( newVertices[index].X / width, 1 - (newVertices[index].Y / height)); } this.Vertices = vertices; //set up indices this.Indices = new short[] { 0, 1, 2 }; }
To put the 3 points in clockwise order, you can use counter-clockwise test (or left-turn test) to check the direction of the 3 points. Pseudocode from Wikipedia # Three points are a counter-clockwise turn if ccw > 0, clockwise if # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that # gives the signed area of the triangle formed by p1, p2 and p3. function ccw(p1, p2, p3): return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) If the 3 points are counter-clockwise, you can just swap the last 2 points to make the 3 points clockwise order.