C# 开发游戏-如何执行需要多个游戏循环的事情?
我使用的是C#,但这适用于用任何语言开发游戏 大多数游戏都使用“游戏循环”,看起来像这样:C# 开发游戏-如何执行需要多个游戏循环的事情?,c#,language-agnostic,events,loops,C#,Language Agnostic,Events,Loops,我使用的是C#,但这适用于用任何语言开发游戏 大多数游戏都使用“游戏循环”,看起来像这样: while (game is running) { UpdateEnvironment(); DrawEnvironment(); } class AI { StateEnum State; //Idle, Moving, Attacking, Dying, etc. PointF Location; PointF Velocity; PointF Destination
while (game is running)
{
UpdateEnvironment();
DrawEnvironment();
}
class AI
{
StateEnum State; //Idle, Moving, Attacking, Dying, etc.
PointF Location;
PointF Velocity;
PointF Destination;
我很难理解,需要不止一个游戏循环的事情是如何符合这个等式的。例如,使一个能量球从一个瓷砖漂浮到另一个瓷砖。或者让玩家移动一个瓷砖(不是从一个瓷砖跳到另一个瓷砖,而是为其设置动画)
我想到的最好的办法是计算自上次循环以来经过的时间,并将其传递给对象/方法,以便它能够完成它的任务。但这使得我们很难做以下事情:
AI.MoveTo(10, 20); // Pathfind, then walk the path to this tile.
Player.Shoot(); // Shoot a bullet, and detect collisions and update along the way.
在哪里可以找到有关“执行需要多个游戏循环才能完成的事件”的更多信息?一种方法是存储完整的挂起操作,然后让游戏循环只执行一点点。从动作中引用的游戏对象知道它们所处的状态,因此下一个要执行的位是已知的。虽然还有一些事情要做,但该操作会被添加回待在下一个循环中执行的挂起操作队列中,并且当该操作完成时,它不再被添加回队列中 因此,在您的
MoveTo
示例中,要存储的操作是移动到10,20
,并且每次在游戏循环中,AI
都会向它移动一点。您的shot
示例最好描述为朝某个方向移动的子弹,然后无论它击中什么,都会决定动作是否继续
我没有做过游戏开发,所以我不知道在这个领域是否是这样做的,但这是我在基于事件的系统中做类似事情的方式。事实上,你所说的使用事件时间是相当准确的。如果你熟悉C#,并且还没有这样做,我强烈建议你去看看XNA,或者如果你愿意花点钱,看看“游戏创造者”的Dark GDK.NET 无论如何,这个想法是,对于每个游戏循环,您使用自上次更新以来经过的时间来更新任何“活动”对象。“活动”对象是指仍被视为活动且需要更新的任何对象(例如,敌人、玩家、飞行中的子弹、仍在爆炸的爆炸等)。根据经过的时间、碰撞、火灾造成的损坏等,确定每个对象的下一个状态、位置、健康状况等,然后实现该下一个状态。最后,为每个对象调用绘制过程,并以新状态渲染它们 对于像球员射击这样的事情,你可以做一些事情。注意,这比任何东西都更像是伪代码。希望它能给你一个想法
//Generic Game Class
public class MySweetGame : Game
{
Player _player = new Player(this);
List<Bullet> _bullets = new List<Bullet>();
public List<Bullet> AllBullets()
{
get { return _bullets; }
}
public void Update()
{
//You would obviously need some keyboard/mouse class to determine if a click took place
if(leftMouseButtonClicked)
{
_player.Shoot();
}
//This would be assuming you have an object collection or array to hold all the bullets currently 'live' like the above '_bullets' collection
//This is also assuming elapseGameTime is some built in game time management, like in XNA
foreach(Bullet blt in _bullets)
{
blt.Update(elapsedGameTime);
}
}
}
//Generic Player Class
public class Player()
{
Vector2 _position = new Vector2(0,0);
int _ammunition = 50;
MySweetGame _game;
public Player(MySweetGame game)
{
_game = game;
}
public void Shoot()
{
if(_ammunition > 0){
_game.AllBullets.Add(new Bullet(50, _position));
_ammunition--;
}
}
}
//Generic Bullet Class
public class Bullet()
{
float _metersPerSecond = 0;
Vector2 _position = new Vector2(0, 0);
public Bullet(float metersPerSecond, Vector3 position)
{
_metersPerSecond = metersPerSecond;
_position = position;
}
//Here is the meat you wanted
//We know the speed of the bullet, based on metersPerSecond - which we set when we instantiated this object
//We also know the elapsedGameTime since we last called update
//So if only .25 seconds have passed - we only moved (50 * .25) - and then update our position vector
public void Update(float elapsedGameTime)
{
distanceTraveled = metersPerSecond * elapsedGameTime;
_position.x += distanceTraveled;
}
}
//通用游戏类
公共类MysweetName:游戏
{
玩家_Player=新玩家(此);
列表_项目符号=新列表();
公共列表所有项目符号()
{
获取{return\u bullets;}
}
公共无效更新()
{
//显然,您需要一些键盘/鼠标类来确定是否发生了单击
如果(左鼠标按钮单击)
{
_player.Shoot();
}
//这将假设您有一个对象集合或数组来保存当前“活动”的所有项目符号,就像上面的“项目符号”集合一样
//这也是假设elapseGameTime是一些内置的游戏时间管理,比如XNA
foreach(子弹blt in_子弹)
{
blt.更新(elapsedGameTime);
}
}
}
//通用玩家类
公共类玩家()
{
向量2_位置=新向量2(0,0);
国际单位弹药=50;
MySweetGame_游戏;
公共玩家(MySweetGame游戏)
{
_游戏=游戏;
}
公开射击()
{
如果(_>0){
_游戏。所有子弹。添加(新子弹(50,_位置));
_弹药--;
}
}
}
//通用项目符号类
公共类项目符号()
{
浮点数_metersPerSecond=0;
向量2_位置=新向量2(0,0);
公共项目符号(浮动米秒,矢量3位置)
{
_metersPerSecond=metersPerSecond;
_位置=位置;
}
//这是你要的肉
//我们知道子弹的速度,基于metersPerSecond——我们在实例化这个对象时设置的
//我们还知道自上次调用update以来的elapsedGameTime
//因此,如果只经过了.25秒-我们只移动了(50*.25)-然后更新我们的位置向量
公共无效更新(浮动elapsedGameTime)
{
行驶距离=米/秒*elapsedGameTime;
_位置x+=行驶距离;
}
}
考虑操作系统如何允许多个程序在单个处理器上运行:
- 程序1正在运行
- 程序1被中断
- 程序1的状态(CPU寄存器等的内容)由内核保存
- 程序2的状态由内核加载
- 程序2恢复
然而,通常可以通过某种方式设计您的系统,以减少求助于这种方式的需要。例如,设计动画以便一次只能处理一帧。您可能不会使用事件;相反,MoveTo或Shot应该被视为状态的变化。您的AI对象需要一个由以下变量组成的状态:
while (game is running)
{
UpdateEnvironment();
DrawEnvironment();
}
class AI
{
StateEnum State; //Idle, Moving, Attacking, Dying, etc.
PointF Location;
PointF Velocity;
PointF Destination;
在MoveTo方法中,需要设置对象的状态——类似于:
void MoveTo(x, y)
{
Destination = new PointF(x, y);
Velocity = new PointF(0.5, 0);
State = StateEnum.Moving;
}
然后在其更新方法中,您将更新位置
void Update()
{
switch (State)
{
case StateEnum.Moving:
Location.Offset(Velocity); //advance 0.5 pixels to the right
break;
default:
break;
}
}
}
该方法将根据某个计时器(例如每秒60次)从游戏循环中调用,因此在e