Monogame - 切场景方法?
Monogame - Cut scene methods?
我想创造什么
所以我正在使用 Monogame 构建一个 2D 冒险游戏,在游戏开始时,我想使用 3 张图片 来显示之前的故事情节,有点像介绍过场动画,因此每张图片都显示了游戏中故事开始的不同快照。
我希望它如何工作
我希望它只显示一张图片,然后与第二张图片重叠,然后是第三张图片,每张图片之间暂停约 3 秒(根本不关心过渡)。
我对所有读者的提问
我想知道,什么是最好的实现方式,以便它在我的游戏开始时开始?我正在考虑在 Premier Pro 之类的东西上制作过场动画,它只是一个播放的视频,但我不确定是否有更好的选择来做到这一点。 我只想知道实现这样的目标的最简单方法是什么。
最好用一两句话准确定义您想要的内容,这样您就可以简单地对其进行编码。我个人将过场动画定义为:"List of images that fade in from black screen, stay there a bit, then fade to black. You can skip one image by pressing a single keyboard button (like spacebar)." 这意味着我将包括计时器和图像。这样我就知道每张图片以及整个幻灯片的完整播放时间。
我有一些旧代码可能会对您有所帮助。此代码获取要显示的图像列表、淡入时间、待机时间和淡出时间。通过将 fade-in/out-to-black 效果切换为淡入淡出重叠效果,可以轻松将其转换为您想要的效果。
首先这里是单屏class:
using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace F.U.N
{
public class SplashScreen
{
public enum Status
{
Ready,
FadingIn,
Waiting,
FadingOut,
NotReady
}
private Status currentStatus;
public Status CurrentStatus { get { return currentStatus; } }
private Texture2D image;
private Color color;
private byte fade;
private float timer,
fadeInTime,
waitTime,
fadeOutTime;
private float startToWaitTime { get { return fadeInTime; } }
private float startToFadeOutTime { get { return fadeInTime + waitTime; } }
private float startToEndTime { get { return fadeInTime + waitTime + fadeOutTime; } }
public SplashScreen(Texture2D image, float fadeInTime, float waitTime, float fadeOutTime)
{
float min = 0.1f;
this.image = image;
this.fadeInTime = Math.Max(fadeInTime, min);
this.waitTime = Math.Max(waitTime, min);
this.fadeOutTime = Math.Max(fadeOutTime, min);
Prepare();
}
public void Prepare()
{
fade = 0;
timer = 0;
color = new Color(fade, fade, fade);
currentStatus = Status.Ready;
}
public void Update(GameTime gt)
{
//CALCULATE ALPHA & status
if (timer < startToWaitTime)
{
fade = (byte)((byte.MaxValue * timer) / startToWaitTime);
if (currentStatus != Status.FadingIn) currentStatus = Status.FadingIn;
}
else if (timer < startToFadeOutTime)
{
if (color.A < byte.MaxValue) color.A = byte.MaxValue;
if (currentStatus != Status.Waiting) currentStatus = Status.Waiting;
}
else if (timer < startToEndTime)
{
fade = (byte)(byte.MaxValue - ((byte.MaxValue * (timer - startToFadeOutTime)) / fadeOutTime));
if (currentStatus != Status.FadingOut) currentStatus = Status.FadingOut;
}
else
{
fade = byte.MinValue;
if (currentStatus != Status.NotReady) currentStatus = Status.NotReady;
}
//UPDATE COLOR AND TIME
color = new Color(fade, fade, fade);
timer += (float)gt.ElapsedGameTime.TotalSeconds;
}
public void Draw(SpriteBatch sp)
{
sp.Draw(image, new Vector2(), color);
}
public void End()
{
currentStatus = Status.NotReady;
}
}
}
现在,这里是创建这些 SpalshScreens 序列的管理器或 "parent" class:
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace F.U.N
{
public class SplashScreenManager
{
private List<SplashScreen> screens;
private Keys skipButton;
public bool Running
{
get
{
foreach (SplashScreen s in screens)
if (s.CurrentStatus != SplashScreen.Status.NotReady)
return true;
return false;
}
}
public SplashScreenManager() : this(new List<SplashScreen>(), Keys.None) { }
public SplashScreenManager(List<SplashScreen> screens, Keys skipButton)
{
this.screens = screens;
this.skipButton = skipButton;
Prepare();
}
public SplashScreenManager(string path, float fadeIn, float wait, float fadeOut, Keys skipButton)
{
List<Texture2D> images = GContent.Textures(path);
screens = new List<SplashScreen>();
foreach (Texture2D t in images)
screens.Add(new SplashScreen(t, fadeIn, wait, fadeOut));
this.skipButton = skipButton;
}
public void Prepare()
{
foreach (SplashScreen s in screens)
s.Prepare();
}
public void Update(GameTime gt)
{
for (int i = 0; i < screens.Count(); i++)
{
if (screens[i].CurrentStatus != SplashScreen.Status.NotReady)
{
screens[i].Update(gt);
if (KState.Clicked(skipButton)) screens[i].End();
break;
}
}
}
public void Draw(SpriteBatch sp)
{
for (int i = 0; i < screens.Count(); i++)
{
if (screens[i].CurrentStatus != SplashScreen.Status.NotReady)
{
screens[i].Draw(sp);
break;
}
}
}
}
}
使用方法:
protected override void LoadContent()
{
//SPLASH SCREEN
ssm = new SplashScreenManager(@"Splash\Pictures", 3, 1, 3, Keys.Space);
}
protected override void Update(GameTime gameTime)
{
if (currentGameState == GameState.Initialize)
{
ssm.Update(gameTime);
if (!ssm.Running)
currentGameState = GameState.Menu;
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.DeepSkyBlue);
switch (currentGameState)
{
case GameState.Initialize:
spriteBatch.Begin();
ssm.Draw(spriteBatch);
spriteBatch.End();
break;
}
}
SplashScreenManager 的构造函数注意事项:GContent.Textures(path);
的目标是尝试加载该文件夹中的所有图像。这个函数看起来像这样:
public static List<Texture2D> Textures(string folderPath)
{
if (!folderPath.StartsWith(@"\")) folderPath = @"\" + folderPath;
List<string> paths = Directory.GetFiles(Help.RootDir(Content.RootDirectory) + folderPath).ToList();
List<Texture2D> images = new List<Texture2D>();
foreach (string s in paths)
{
if (s.EndsWith(".xnb"))
images.Add(Texture(s.Replace(Content.RootDirectory, "").Replace(".xnb", "")));
}
return images;
}
这里 Help.RootDir
只是 returns 根目录,像这样:
public static string RootDir(string s)
{
return s.Substring(0, s.LastIndexOf(@"\"));
}
这样您就可以将所有启动图像放在一个文件夹中。 Offcorse,这取决于你想如何管理你的资源。这是一种非常简单的方法,具有一些强大的功能。尝试在后台使用旧的 sony play station 声音对其进行测试,并将这些参数用于 SSM:ssm = new SplashScreenManager(<em>your list of splash images</em>, 3, 1, 3 )
。看起来和听起来都很棒。如果对您有帮助,请点个赞!
编辑:
我没有告诉你如何在游戏开始时玩这个。使用枚举来定义您的游戏状态,并使用单个变量来存储该信息,如下所示:
public enum GameState
{
Initialize,
Menu,
Level,
MapMaker
}
public GameState currentGameState = GameState.Initialize;
在游戏开始时,设置 currentGameState = GameState.Initialize;
,加载 ssm,并在更新中检查 ssm(启动画面管理器)是否已结束播放。如果是,将currentGameState
改为GameState.Menu
,在Update
方法中使用一个switch
函数,这样你就知道你的游戏当前处于哪个游戏状态,所以你知道什么更新。你在上面的代码中有这样的例子,但我没有写那个,这就是这次编辑的原因。
我想创造什么
所以我正在使用 Monogame 构建一个 2D 冒险游戏,在游戏开始时,我想使用 3 张图片 来显示之前的故事情节,有点像介绍过场动画,因此每张图片都显示了游戏中故事开始的不同快照。
我希望它如何工作
我希望它只显示一张图片,然后与第二张图片重叠,然后是第三张图片,每张图片之间暂停约 3 秒(根本不关心过渡)。
我对所有读者的提问
我想知道,什么是最好的实现方式,以便它在我的游戏开始时开始?我正在考虑在 Premier Pro 之类的东西上制作过场动画,它只是一个播放的视频,但我不确定是否有更好的选择来做到这一点。 我只想知道实现这样的目标的最简单方法是什么。
最好用一两句话准确定义您想要的内容,这样您就可以简单地对其进行编码。我个人将过场动画定义为:"List of images that fade in from black screen, stay there a bit, then fade to black. You can skip one image by pressing a single keyboard button (like spacebar)." 这意味着我将包括计时器和图像。这样我就知道每张图片以及整个幻灯片的完整播放时间。
我有一些旧代码可能会对您有所帮助。此代码获取要显示的图像列表、淡入时间、待机时间和淡出时间。通过将 fade-in/out-to-black 效果切换为淡入淡出重叠效果,可以轻松将其转换为您想要的效果。
首先这里是单屏class:
using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace F.U.N
{
public class SplashScreen
{
public enum Status
{
Ready,
FadingIn,
Waiting,
FadingOut,
NotReady
}
private Status currentStatus;
public Status CurrentStatus { get { return currentStatus; } }
private Texture2D image;
private Color color;
private byte fade;
private float timer,
fadeInTime,
waitTime,
fadeOutTime;
private float startToWaitTime { get { return fadeInTime; } }
private float startToFadeOutTime { get { return fadeInTime + waitTime; } }
private float startToEndTime { get { return fadeInTime + waitTime + fadeOutTime; } }
public SplashScreen(Texture2D image, float fadeInTime, float waitTime, float fadeOutTime)
{
float min = 0.1f;
this.image = image;
this.fadeInTime = Math.Max(fadeInTime, min);
this.waitTime = Math.Max(waitTime, min);
this.fadeOutTime = Math.Max(fadeOutTime, min);
Prepare();
}
public void Prepare()
{
fade = 0;
timer = 0;
color = new Color(fade, fade, fade);
currentStatus = Status.Ready;
}
public void Update(GameTime gt)
{
//CALCULATE ALPHA & status
if (timer < startToWaitTime)
{
fade = (byte)((byte.MaxValue * timer) / startToWaitTime);
if (currentStatus != Status.FadingIn) currentStatus = Status.FadingIn;
}
else if (timer < startToFadeOutTime)
{
if (color.A < byte.MaxValue) color.A = byte.MaxValue;
if (currentStatus != Status.Waiting) currentStatus = Status.Waiting;
}
else if (timer < startToEndTime)
{
fade = (byte)(byte.MaxValue - ((byte.MaxValue * (timer - startToFadeOutTime)) / fadeOutTime));
if (currentStatus != Status.FadingOut) currentStatus = Status.FadingOut;
}
else
{
fade = byte.MinValue;
if (currentStatus != Status.NotReady) currentStatus = Status.NotReady;
}
//UPDATE COLOR AND TIME
color = new Color(fade, fade, fade);
timer += (float)gt.ElapsedGameTime.TotalSeconds;
}
public void Draw(SpriteBatch sp)
{
sp.Draw(image, new Vector2(), color);
}
public void End()
{
currentStatus = Status.NotReady;
}
}
}
现在,这里是创建这些 SpalshScreens 序列的管理器或 "parent" class:
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace F.U.N
{
public class SplashScreenManager
{
private List<SplashScreen> screens;
private Keys skipButton;
public bool Running
{
get
{
foreach (SplashScreen s in screens)
if (s.CurrentStatus != SplashScreen.Status.NotReady)
return true;
return false;
}
}
public SplashScreenManager() : this(new List<SplashScreen>(), Keys.None) { }
public SplashScreenManager(List<SplashScreen> screens, Keys skipButton)
{
this.screens = screens;
this.skipButton = skipButton;
Prepare();
}
public SplashScreenManager(string path, float fadeIn, float wait, float fadeOut, Keys skipButton)
{
List<Texture2D> images = GContent.Textures(path);
screens = new List<SplashScreen>();
foreach (Texture2D t in images)
screens.Add(new SplashScreen(t, fadeIn, wait, fadeOut));
this.skipButton = skipButton;
}
public void Prepare()
{
foreach (SplashScreen s in screens)
s.Prepare();
}
public void Update(GameTime gt)
{
for (int i = 0; i < screens.Count(); i++)
{
if (screens[i].CurrentStatus != SplashScreen.Status.NotReady)
{
screens[i].Update(gt);
if (KState.Clicked(skipButton)) screens[i].End();
break;
}
}
}
public void Draw(SpriteBatch sp)
{
for (int i = 0; i < screens.Count(); i++)
{
if (screens[i].CurrentStatus != SplashScreen.Status.NotReady)
{
screens[i].Draw(sp);
break;
}
}
}
}
}
使用方法:
protected override void LoadContent()
{
//SPLASH SCREEN
ssm = new SplashScreenManager(@"Splash\Pictures", 3, 1, 3, Keys.Space);
}
protected override void Update(GameTime gameTime)
{
if (currentGameState == GameState.Initialize)
{
ssm.Update(gameTime);
if (!ssm.Running)
currentGameState = GameState.Menu;
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.DeepSkyBlue);
switch (currentGameState)
{
case GameState.Initialize:
spriteBatch.Begin();
ssm.Draw(spriteBatch);
spriteBatch.End();
break;
}
}
SplashScreenManager 的构造函数注意事项:GContent.Textures(path);
的目标是尝试加载该文件夹中的所有图像。这个函数看起来像这样:
public static List<Texture2D> Textures(string folderPath)
{
if (!folderPath.StartsWith(@"\")) folderPath = @"\" + folderPath;
List<string> paths = Directory.GetFiles(Help.RootDir(Content.RootDirectory) + folderPath).ToList();
List<Texture2D> images = new List<Texture2D>();
foreach (string s in paths)
{
if (s.EndsWith(".xnb"))
images.Add(Texture(s.Replace(Content.RootDirectory, "").Replace(".xnb", "")));
}
return images;
}
这里 Help.RootDir
只是 returns 根目录,像这样:
public static string RootDir(string s)
{
return s.Substring(0, s.LastIndexOf(@"\"));
}
这样您就可以将所有启动图像放在一个文件夹中。 Offcorse,这取决于你想如何管理你的资源。这是一种非常简单的方法,具有一些强大的功能。尝试在后台使用旧的 sony play station 声音对其进行测试,并将这些参数用于 SSM:ssm = new SplashScreenManager(<em>your list of splash images</em>, 3, 1, 3 )
。看起来和听起来都很棒。如果对您有帮助,请点个赞!
编辑:
我没有告诉你如何在游戏开始时玩这个。使用枚举来定义您的游戏状态,并使用单个变量来存储该信息,如下所示:
public enum GameState
{
Initialize,
Menu,
Level,
MapMaker
}
public GameState currentGameState = GameState.Initialize;
在游戏开始时,设置 currentGameState = GameState.Initialize;
,加载 ssm,并在更新中检查 ssm(启动画面管理器)是否已结束播放。如果是,将currentGameState
改为GameState.Menu
,在Update
方法中使用一个switch
函数,这样你就知道你的游戏当前处于哪个游戏状态,所以你知道什么更新。你在上面的代码中有这样的例子,但我没有写那个,这就是这次编辑的原因。