在不同位置产卵球(初学者问题) [英] spawning ball at different positions(beginner question)

查看:72
本文介绍了在不同位置产卵球(初学者问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先我的代码:



主要游戏类:

 使用系统; 
使用 System.Collections.Generic;
使用 System.Linq;
使用 Microsoft.Xna.Framework;
使用 Microsoft.Xna.Framework.Audio;
使用 Microsoft.Xna.Framework.Content;
使用 Microsoft.Xna.Framework.GamerServices;
使用 Microsoft.Xna.Framework.Graphics;
使用 Microsoft.Xna.Framework.Input;
使用 Microsoft.Xna.Framework.Media;

命名空间 WindowsGame2
{
/// < 摘要 >
/// 这是您游戏的主要类型
/// < / summary >
public class Game1:Microsoft.Xna.Framework.Game
{
public 静态 GraphicsDeviceManager图形;
public static SpriteBatch spriteBatch;
public 静态 Texture2D火箭,火焰;
public static KeyboardState状态;
public static SpriteFont字体;
public static Texture2D ball;
public Game1()

{
graphics = new GraphicsDeviceManager( this );
Content.RootDirectory = 内容;
IsMouseVisible = true ;
graphics.ApplyChanges();

}

/// < 摘要 >
< span class =code-summarycomment> /// 允许游戏在开始运行之前执行所需的任何初始化。
/// 这是它可以查询任何所需服务并加载任何非服务的地方graphic
/// 相关内容。调用base.Initialize将枚举任何组件
/// 并初始化它们。
/// < / summary >
protected 覆盖 void Initialize()
{
// TODO:在此处添加初始化逻辑
base .Initialize();


}

/// < 摘要 >
/// 每个游戏将调用一次LoadContent,并且是加载
/// 您的所有内容。
/// < / summary >
protected 覆盖 void LoadContent()
{
// 创建一个新的SpriteBatch,可用于绘制纹理。
spriteBatch = new SpriteBatch(GraphicsDevice);
rocket = Content.Load< Texture2D>( rocket);
font = Content.Load< SpriteFont>( SpriteFont1);
ball = Content.Load< Texture2D>( ball);
flame = Content.Load< Texture2D>( flame);
// TODO:使用this.Content在此处加载您的游戏内容
}

/// < 摘要 >
/// UnloadContent将在每场比赛中被调用一次,并且是卸载
的地方
/ // 所有内容。
/// < / summary >
protected 覆盖 void UnloadContent()
{
// TODO:在此处卸载任何非ContentManager内容
}

< span class =code-summarycomment> ///
< 摘要 >
/// 允许游戏运行逻辑,例如更新世界,
/// 检查冲突,收集输入和播放音频。
/// < / summary >
/// < param < span class =code-summarycomment> name =gameTime > 提供时间值的快照。< / param >
受保护 覆盖 void 更新(GameTime gameTime)
{
state = Keyboard.GetState();
// 允许游戏退出
if (GamePad.GetState(PlayerIndex.One)。Buttons.Back == ButtonState.Pressed)
this .Exit() ;
// TODO:在此处添加更新逻辑
.Update(gameTime);
}

/// < 摘要 >
/// 当游戏自行绘制时调用。
/// < / summary >
/// < param < span class =code-summarycomment> name =gameTime > 提供时间值的快照。< / param >
受保护 覆盖 void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
// TODO:在此处添加您的绘图代码
Ball.Generatenewball() ;
base .Draw(gameTime);
}
}
}





球类:

< pre lang =c#> 使用系统;
使用 System.Collections.Generic;
使用 System.Linq;
使用 Microsoft.Xna.Framework;
使用 Microsoft.Xna.Framework.Audio;
使用 Microsoft.Xna.Framework.Content;
使用 Microsoft.Xna.Framework.GamerServices;
使用 Microsoft.Xna.Framework.Graphics;
使用 Microsoft.Xna.Framework.Input;
使用 Microsoft.Xna.Framework.Media;


命名空间 WindowsGame2
{
public class Ball
{
public static Random rand = new Random();
private static int width ,身高,动作,我;
public static 列表< Ball> balls = new List< Ball>();
public Ball()
{
width = rand.Next( 1 ,GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width);
height = rand.Next( 1 ,GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height);}
公开 静态 void 更新()
{
movement = rand .Next( 1 5 );
if (move == 1
{
if (height < = -50)
{height = 800 ; }
height - = 10 ;
}
如果(移动== 2
{
if (height > = 800
{height = -50; }
height + = 10 ;
}
如果(行动== 3
{
if (width > = 1350
{width = -30; }
width + = 10 ;
}
如果(移动== 4
{
if (width < = -30)
{width = 1350 ; }
width - = 10 ;
}
}
public static void Draw()
{Game1.spriteBatch.Begin();
Game1.spriteBatch.Draw(Game1.ball, new Vector2(width,height),Color.White);
Game1.spriteBatch.End();}
public static void Generatenewball()
{
i ++;
if (i% 500 == 0
{
balls.Add( new Ball());
}
foreach (Ball ball in balls)
{Draw ();
Update();
}

}
}
}





我想要每隔一段时间产生一个新球。产生一个新球,但所有球都在一个位置并一起移动。我想在屏幕周围的不同位置使用不同的球。我知道我做错了,请纠正我和给出正确的代码。

解决方案

不要将Random放在Ball类中。相反,将它传递给构造函数。一个更好的方法是将Random类包装在一个接口中,这样就可以提供随机数生成器的各种实现,这对于测试应用程序特别有用。这称为依赖注入。



使用它自己的RNG代替Ball类,它可以使用调用代码传递给它的Random实现。





你遇到的问题是你的代码创建了一堆Ball实例,其中一个或多个可以使用默认种子值,它是当前的Timer值。在这种情况下,每个随机类都会踢出相同的随机数字序列。



你修改过的Ball类:

公共课Ball 
{
IRandom rng;

private Ball()
{
//private删除无参数构造函数。
//这会强制您的代码提供IRandom实现。
}

public Ball(IRandom random)
{
if(random == null)
{
throw new ArgumentNullException(random );
}

rng =随机;
}

... snip 8< ...
}



IRandom界面:

公共界面IRandom 
{
int Next();
int Next(int);
double NextDouble();
}





您的默认IRandom实施:

 public class DefaultRandom:IRandom 
{
Random rng;

public DefaultRandom()
{
rng = new Random();
}

public DefaultRandom(int seed)
{
rng = new Random(seed);
}

public int Next()
{
return rng.Next();
}

public int Next(int ceiling)
{
return rng.Next(ceiling);
}

public double NextDouble()
{
return rng.NextDouble();
}

}





最后,在您的游戏代码中,您只需创建一个IRandom实现的实例并将其传递给您的Ball。您的游戏应该只有一个IRandom,然后您可以将其传递给任意数量的对象。一切都可以使用相同的RNG:

 DefaultRandom rng = new DefaultRandom(); 

// ... snip 8< ...

Ball myBall = new Ball(rng);


First my code:

Main game class:

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 WindowsGame2
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
       public static GraphicsDeviceManager graphics;
       public static SpriteBatch spriteBatch;
       public static Texture2D rocket,flame;
       public static KeyboardState state;
       public static SpriteFont font;
       public static Texture2D ball;
        public Game1()
           
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
            graphics.ApplyChanges();
            
        }

        /// <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);
            rocket = Content.Load<Texture2D>("rocket");
            font = Content.Load<SpriteFont>("SpriteFont1");
            ball = Content.Load<Texture2D>("ball");
            flame = Content.Load<Texture2D>("flame");
            // 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)
        {
            state = Keyboard.GetState();
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();            
            // TODO: Add your update logic here
            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.White);
            // TODO: Add your drawing code here
            Ball.Generatenewball();
            base.Draw(gameTime);
        }
    }
}



Ball class:

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 WindowsGame2
{      
    public class Ball
    {
        public static Random rand=new Random();
        private static int width, height,movement,i;
        public static List<Ball> balls = new List<Ball>();
        public Ball()
        {
            width = rand.Next(1,GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width);
        height=rand.Next(1,GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height);}
        public static void Update()
        {
            movement = rand.Next(1, 5);
            if (movement == 1)
            {
                if (height <= -50)
                { height = 800; }
                height -= 10;
            }
            if (movement == 2)
            {
                if (height >= 800)
                { height = -50; }
                height += 10;
            }
            if (movement == 3)
            {
                if (width >= 1350)
                { width = -30; }
                width += 10;
            }
            if (movement == 4)
            {
                if (width <= -30)
                { width = 1350; }
                width -= 10;
            }
        }
        public static void Draw()
        {Game1.spriteBatch.Begin();
        Game1.spriteBatch.Draw(Game1.ball, new Vector2(width, height), Color.White);
        Game1.spriteBatch.End();}
        public static void Generatenewball()
        {
            i++;
            if (i % 500 == 0)
            {
                balls.Add(new Ball());
            }
            foreach (Ball ball in balls) 
            {Draw();
            Update();
            }
            
         }
        }
    }



I want to spawn a new ball at regular intervals.A new ball is spawned,but all the balls are at a single position and move together.I want different balls at different positions around the screen.I know I am doing something wrong,please correct me and give the correct code.

解决方案

Don't put your Random in the Ball class. Instead, pass it into the constructor. A better method would be to wrap the Random class in an Interface so you can supply various implementations of random number generators, especially useful for testing your application. This is called "dependency injection".

Instead of the Ball class using it's own RNG, it'll can use a Random implementation passed to it by the calling code.


The problem that you're running into is when your code creates a bunch of instances of Ball, one or more of them can use the default seed value which is the current Timer value. In that case, each one of those Random classes will kick out the same sequence of "random" numbers.

Your modified Ball class:

public class Ball
{
    IRandom rng;

    private Ball()
    {
        // "private" removes the parameterless constructor.
        // This forces your code to provide a IRandom implementation.
    }

    public Ball(IRandom random)
    {
        if (random == null)
        {
            throw new ArgumentNullException("random");
        }

        rng = random;
    }

    ... snip 8< ...
}


The IRandom interface:

public interface IRandom
{
    int Next();
    int Next(int);
    double NextDouble();
}



Your "default" IRandom implementation:

public class DefaultRandom : IRandom
{
    Random rng;

    public DefaultRandom()
    {
        rng = new Random();
    }

    public DefaultRandom(int seed)
    {
        rng = new Random(seed);
    }

    public int Next()
    {
        return rng.Next();
    }

    public int Next(int ceiling)
    {
        return rng.Next(ceiling);
    }

    public double NextDouble()
    {
        return rng.NextDouble();
    }

}



Finally, in your game code, you simply create an instance of your IRandom implementation and pass it to your Ball. Your game should have only one IRandom and you can then pass that to as many objects as you want. Everything would work off of the same RNG:

DefaultRandom rng = new DefaultRandom();

// ... snip 8< ...

Ball myBall = new Ball(rng);


这篇关于在不同位置产卵球(初学者问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆