C# XNA - Problem med kollision

Permalänk
Medlem

C# XNA - Problem med kollision

Jag håller på och försöker lära mig att göra spel i XNA men har kört fast. Jag har en sprite som är animerad via ett spritesheet. Sprite:en ska åka horisontellt och studsa fram och tillbaka mellan fönstrets kanter, men istället för att ändra riktning när sprite:en slår i den högra väggen så stannar den och börjar flimra vitt. Den sitter alltså fast i väggen och ändrar riktning varje frame så att den inte kommer någonstans.

Jag har använt exakt samma logik i ett annat program med oanimerade sprites för att de ska studsa och där funkar det.

Hela programmet:

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; namespace AnimatedSprites { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D texture; Vector2 pos = Vector2.Zero; Point frameSize = new Point(75, 75); Point currentFrame = new Point(0, 0); Point sheetSize = new Point(6,8); int timeSinceLastFrame = 0; int millisecondsPerFrame = 50; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); texture = Content.Load<Texture2D>(@images\threerings); // TODO: use this.Content to load your game content here } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); pos.X += 5; //pos.Y += 5; if (pos.X <= 0 || pos.X >= Window.ClientBounds.Width - frameSize.X) pos.X *= -1; timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; if (timeSinceLastFrame > millisecondsPerFrame) { timeSinceLastFrame -= millisecondsPerFrame; ++currentFrame.X; if (currentFrame.X >= sheetSize.X) { currentFrame.X = 0; ++currentFrame.Y; if (currentFrame.Y >= sheetSize.Y) currentFrame.Y = 0; } } base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend); spriteBatch.Draw(texture, pos, new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); } } }

Dold text
Permalänk
Medlem

Du behöver en variabel som anger den nuvarande riktningen.

int dx = speedX; ... pos.X += dx; if (pos.X <= 0) { dx = speedX; pox.X = 0; } else if (pos.X >= (Window.ClientBounds.Width - frameSize.X)) { dx = -speedx; pos.X = (Window.ClientBounds.Width - frameSize.X); }

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk
Medlem

Jag multiplicerade positionen istället för hastigheten med -1 och såg inte det, nu får man skämmas

Permalänk
Medlem

kan tillägga att efter en snabb genomgång av koden så skall du använda gameTime.ElapesedGameTime.TotalMilliseconds annars får du ett värde mellan 0 and 999 vilket kan göra att din "timeSinceLastFrame" blir negativ (-999)

Rätta mig om jag har fel dock. Var ett tag sedan jag meckade .net och speciellt XNA.

EDIT: Och orginalkoden funkar inte för att detta händer...

Säg att ditt fönster är 820 pixlar brett och din "frame" är 20 pixlar bred.

x += 5 <--- varje iteration.

x är 0
x är 5
x är 10
...
x är 795
x är 800

if satsen triggas, x *= -1, x är -800!

x += 5

x är -795

if satsen triggas, x *= -1, x är 795!

x+= 5

x är 800

if satsen triggas, x *= -1, x är -800!

Så fortsätter det alltså och därför flimrar det och har sig!
Man måste alltså ha en riktnings variabel som man inverterar vid kollision.

riktning = 5

x += riktning

if satsen sätter riktning *= -1 och riktning blir -5! (Eller +5 om x <= 0)

Nu vet du varför det inte fungerade!
* -1 är rätt men tillämpningen är FEL.

riktning = -riktning fungerar lika bra men är mer skrivande. Om man förståss inte har en speed variabel då.

Visa signatur

Chassi: Svart, PSU: 230 volt, Moderkort: Stort, CPU: Med fläkt, Minne: Tappat, GPU: Klarar MsPaint jättebra, Hårddiskar: Stor och liten, Mus: Med rullhjul, Tangentbord: Svenskt, Skärm: Platt

Permalänk

Jag tror jag har samma problem. Jag multiplicerar farten med -1, men då står bara bilden och hackar tills man rör lite på piltangenterna(Har gjort ett Pong-spel). Förstår inte varför det inte fungerar.

Hjälp!

Visa signatur
Permalänk
Medlem
Skrivet av Kebabhyvlarn:

Jag tror jag har samma problem. Jag multiplicerar farten med -1, men då står bara bilden och hackar tills man rör lite på piltangenterna(Har gjort ett Pong-spel). Förstår inte varför det inte fungerar.

Hjälp!

Antar att du har en vector2 förhastighet, och en vector2 för position.
Jag skulle gjort det så här.

Två if-satser som kollar om bollen är utanför något fönster, om det är utanför det högra eller vänstra fönstret inverteras x-hastigheten, om positionen är utanför det övre eller undre (stavning?) fönstret inverteras y-hastigheten.

Variabler Vector2 position = new Vector2(200,200); Vector2 velocity = New Vector2(5,5); Texture texture; Update if (position.X < 0 || position.X + texture.Width > GraphicsDevice.Viewport.Width) velocity.X = -velocity.X; if (position.Y < 0 || position.Y + texture.Height > GraphicsDevice.Viewport.Height) velocity.Y = -velocity.Y; position += velocity;