背景
收到一个游戏开发的需求,因为双端上线所以需要支持iOS Android两端.
3个Android RD,没有接触过游戏开发,快速学习上手Flutter支持双端.
计划游戏使用Flame框架,先大题熟悉下环境然后在开发的过程中学习和解决问题.
知识点
GameLoop是什么
游戏循环就是搭建一个游戏的脚手架.大部分游戏只需要2个方法即:
render方法
用来绘制
update方法
用来更新绘制参数. update当前帧和上一帧的差异.
比如表现一个正在下坠的圆
圆的坐标用y表示. render方法负责拿着y值去绘制圆, update方法负责更新y的变化. 互相配合完成了一个圆的下坠动画
如何把一个Flutter组件展示在Frame引擎上
利用 HasWidgetsOverlay 接口.
用removeWidgetOverlay方法移出Flutter组件
用addWidgetOverlay方法添加Flutter组件
class MyGame extends BaseGame with HasWidgetsOverlay, TapDetector {
Size size;
SpriteC spriteC;
bool isPaused = false;
MyGame(this.size) {
spriteC = SpriteC.create();
}
@override
void onTap() {
super.onTap();
if (isPaused) {
removeWidgetOverlay('pausemenu');
isPaused = false;
} else {
addWidgetOverlay(
'pausemenu',
Center(
child: Container(
width: 100,
height: 100,
color: Colors.blue[300],
child: const Center(child: const Text('Pause')),
),
));
isPaused = true;
}
}
}
复制代码
如何把游戏展示在Flutter的一个组件上
Game提供一个Widget对象,可以直接获取最为Flutter的一个Widget使用.
final game = MyGame(size);
runApp(game.widget);
复制代码
Debug功能是什么
@override
bool debugMode() => true;
@override
bool recordFps() => true;
复制代码
开启Debug.
Debug就是允许调试,会自动打印组件的位置.
recordFps就是输出当前运行游戏的FPS.
组件(Components)
必要性:
就跟在Android/iOS上糊页面一样. 所有的页面,动画,特效都可以用Canvas来画, 实际上开发一般情况下用的却是ImageView,TextView,ListView这样的组件来完成. 没有人喜欢刀耕火种
组件重要方法:
除了render 和 update这种通用方法.
// 初始化
@override
void onMount() {
super.onMount();
}
// 回收前
@override
void onDestroy() {
super.onDestroy();
}
// 还没搞清楚...? 好像在说绘制的位置跟设备之间的关系
@override
bool isHud() {
return true;
}
// 标记可回收
@override
bool destroy() {
return false;
}
复制代码
怎么画帧动画
即把
变成
游戏里面的人都是会动的,所以这是一个重要知识点.
在游戏里面展示 AnimationComponent
const textureWidth = 96.0;
const textureHeight = 96.0;
add(AnimationComponent.sequenced(
textureWidth * 2,
textureHeight * 2,
'minotaur.png',
19,
textureWidth: textureWidth,
textureHeight: textureHeight,
loop: true,
stepTime: 0.15,
));
复制代码
其中函数 AnimationComponent.sequenced 的参数说明如下:
AnimationComponent.sequenced(
double width, // 展示的宽度
double height, // 展示的高度
String imagePath,
int amount, { // Sprit Sheet的帧数
int amountPerRow, // 多行切图 两行之间的间隔
double textureX = 0.0, // 展示的偏移值
double textureY = 0.0,
double textureWidth, // 切图一帧的宽度
double textureHeight, // 切图一帧的高度
double stepTime, // 播放间隔时间
bool loop = true, // 是否循环播放
this.destroyOnFinish = false, // 播放完了是否销毁
})
复制代码
提供给Flutter组件展示 AnimationWidget
await Flame.images.load('minotaur.png');
final _animationSpriteSheet = SpriteSheet(
imageName: 'minotaur.png',
columns: 19,
rows: 1,
textureWidth: 96,
textureHeight: 96,
);
_animation = _animationSpriteSheet.createAnimation(
0,
stepTime: 0.2,
to: 5,
);
// 使用
Container(
width: 200,
height: 200,
child: AnimationWidget(animation: _animation),
),
复制代码
怎么画SVG动画 SvgComponent
Svg svg = Svg('android.svg');
SvgComponent android = SvgComponent.fromSvg(100, 100, svg);
android.x = 100;
android.y = 100;
复制代码
怎么画组合控件 ComposedComponent
和原生组合控件相似的做法.
class GameOverPanel extends PositionComponent
with Resizable, HasGameRef, Tapable, ComposedComponent {
GameOverPanel(Image spriteImage) : super() {
gameOverText = GameOverText(spriteImage);
gameOverRestart = GameOverRestart(spriteImage);
components..add(gameOverText)..add(gameOverRestart);
}
bool visible = false;
GameOverText gameOverText;
GameOverRestart gameOverRestart;
@override
void render(Canvas canvas) {
if (visible) {
super.render(canvas);
}
}
}
class GameOverText extends SpriteComponent with Resizable {
GameOverText(Image spriteImage)
: super.fromSprite(
GameOverConfig.textWidth,
GameOverConfig.textHeight,
Sprite.fromImage(
spriteImage,
x: 955.0,
y: 26.0,
width: GameOverConfig.textWidth,
height: GameOverConfig.textHeight,
),
);
@override
void resize(Size size) {
if (width > size.width * 0.8) {
width = size.width * 0.8;
}
y = size.height * .25;
x = (size.width / 2) - width / 2;
}
}
class GameOverRestart extends SpriteComponent with Resizable {
GameOverRestart(Image spriteImage)
: super.fromSprite(
GameOverConfig.restartWidth,
GameOverConfig.restartHeight,
Sprite.fromImage(
spriteImage,
x: 2.0,
y: 2.0,
width: GameOverConfig.restartWidth,
height: GameOverConfig.restartHeight,
),
);
@override
void resize(Size size) {
y = size.height * .75;
x = (size.width / 2) - GameOverConfig.restartWidth / 2;
![](https://user-gold-cdn.xitu.io/2020/6/19/172c89c8d5d4aff0?w=304&h=640&f=gif&s=3257550)
}
}
复制代码
怎么绘制视差动画 ParallaxComponent
简单来说就是怎么把
组合起来生成
final images = [
ParallaxImage("bg.png"),
ParallaxImage("mountain-far.png"),
ParallaxImage("mountains.png"),
ParallaxImage("trees.png"),
ParallaxImage("foreground-trees.png"),
];
final parallaxComponent = ParallaxComponent(images,
baseSpeed: const Offset(20, 0), layerDelta: const Offset(100, 0));
复制代码
月亮&天空离我们远所以移动得慢一些
树木离我们近所以移动得快一些
组合起来很神奇,这个效果我很喜欢.TOT
怎么画可拉伸图片(Android的.9.png图) NineTileBox
如下例:
// 定义
final sprite = Sprite('nine-box.png');
nineTileBox = NineTileBox(sprite, tileSize: 8, destTileSize: 24);
// 使用
nineTileBox.draw(canvas, x, y, 200, 500);
复制代码
两个角各占4个像素,合起来就是8个像素, 图片总共24个像素. 这就是上面得参数得含义.
UE切图的话需要保持图片尺寸是3的倍数,另外这里比起.9.png有个缺点是他必须保证4个角是对称的. 对于非对称,比如上面8个像素 下面只需要4个像素的图片不支持.
物理引擎 Box2DComponent
Flame支持Box2D.即组件 Box2DComponent.我理解就是可以实现物理体积 和 碰撞的能力.
这是一个很Powerful得组件,应该会有些深度,需要后面花时间仔细研究下.这里先熟悉他的作用范围就行.
网站:box2d.org/
Box2D是一款免费的开源二维物理引擎,由Erin Catto使用C++编写,在zlib授权下发布。它已被用于蜡笔物理学、愤怒的小鸟、地狱边境、Rolando、Fantastic ...
关于找一找教程网
本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[Flutter Flame游戏开发上手(1)]http://www.zyiz.net/tech/detail-140359.html