How can you set the background color?
I tried setting this in onLoad:
world.color.setRGB(0,0,255);
I also tried adding a component, but I maybe there is a better way:
class Background extends PositionComponent with HasGameRef {
#override
int priority = -1;
late Paint white;
late final Rect hugeRect;
Background() : super(size: Vector2.all(100000));
#override
Future<void> onLoad() async {
white = BasicPalette.blue.paint();
hugeRect = size.toRect();
}
#override
void render(Canvas c) {
c.drawRect(hugeRect, white);
}
}
#override
Color backgroundColor() => const Color(0xFFeeeeee);
Related
I'm trying to change my object(Horse()) anchor point to Anchor.center in the creation of the object. But I wasn't able to. If I change it inside FlameGame using horse.anchor = Anchor.center it works but I want to create it with Anchor.center.
import 'package:flame/components.dart';
class Horse extends SpriteComponent {
final String name;
static const double spriteSize = 64;
#override
set anchor(Anchor anchor) {
super.anchor = Anchor.center;
}
#override
Future<void> onLoad() async {
sprite = await Sprite.load('$name.jpg');
}
Horse(this.name) : super(size: Vector2.all(spriteSize));
}
You can pass in the anchor directly to the super constructor:
import 'package:flame/components.dart';
class Horse extends SpriteComponent {
Horse(this.name) : super(size: Vector2.all(spriteSize), anchor: Anchor.center);
final String name;
static const double spriteSize = 64;
#override
Future<void> onLoad() async {
sprite = await Sprite.load('$name.jpg');
}
}
If you don't want to extend SpriteComponent you can also do this:
final sprite = await loadSprite('horse.jpg');
final spriteSize = 64;
final component = SpriteComponent(
sprite: sprite,
size: Vector2.all(spriteSize),
anchor: Anchor.center,
);
I changed my code to this and it now works but I don't think this is the ideal solution so I still want your answers pls
import 'package:flame/components.dart';
class Horse extends SpriteComponent {
final String name;
static const double spriteSize = 64;
anchorChange() {
super.anchor = Anchor.center;
}
#override
Future<void> onLoad() async {
sprite = await Sprite.load('$name.jpg');
anchorChange();
}
Horse(this.name) : super(size: Vector2.all(spriteSize));
}
I want to listen a webp animation's update event on each webp frame, so I create MyImage. but I can't get onUpdateImage trigger, please help. thx
main.dart
AssetImage loadWebp2() {
print('WEBP::loadWebp2');
final image = 'assets/image/07_OK.webp';
var imageProvider = AssetImage(image);
var myImage = MyImage(imageProvider: imageProvider);
myImage.addListener(MyStateListener());
return imageProvider;
}
class MyStateListener extends StateListener {
#override
void onUpdateImage(ImageInfo imageInfo) {
super.onUpdateImage(imageInfo);
print('WEBP::onUpdateImage, $imageInfo');
}
}
MyImage.dart
import 'package:flutter/cupertino.dart';
class MyImage extends StatefulWidget {
const MyImage({
Key key,
#required this.imageProvider,
})
: assert(imageProvider != null),
super(key: key);
final ImageProvider imageProvider;
#override
_MyImageState createState() => _MyImageState();
}
class _MyImageState extends State<MyImage> {
ImageStream _imageStream;
ImageInfo _imageInfo;
StateListener stateListener;
#override
void didChangeDependencies() {
super.didChangeDependencies();
_getImage();
}
#override
void didUpdateWidget(MyImage oldWidget) {
super.didUpdateWidget(oldWidget);
print('WEBP::didUpdateWidget');
if (widget.imageProvider != oldWidget.imageProvider)
_getImage();
}
void _getImage() {
print('WEBP::_getImage');
final ImageStream oldImageStream = _imageStream;
_imageStream =
widget.imageProvider.resolve(createLocalImageConfiguration(context));
if (_imageStream.key != oldImageStream?.key) {
final ImageStreamListener listener = ImageStreamListener(_updateImage);
oldImageStream?.removeListener(listener);
_imageStream.addListener(listener);
}
}
void _updateImage(ImageInfo imageInfo, bool synchronousCall) {
print('WEBP::_updateImage');
setState(() {
// Trigger a build whenever the image changes.
_imageInfo = imageInfo;
if (stateListener != null) {
stateListener.onUpdateImage(_imageInfo);
}
print('WEBP::_updateImage, setState, $imageInfo');
});
}
#override
void dispose() {
_imageStream.removeListener(ImageStreamListener(_updateImage));
super.dispose();
}
#override
Widget build(BuildContext context) {
print('WEBP::build');
return RawImage(
image: _imageInfo?.image, // this is a dart:ui Image object
scale: _imageInfo?.scale ?? 1.0,
);
}
}
class StateListener {
void onUpdateImage(ImageInfo imageInfo) {}
}
I am completely newbie in flutter world specially flame-engine. Maybe it's a simple issue. But currently I couldn't figure it out. So please help me!
The main issue is my Draggable component doesn't work all event handler functions seem like doesn't not work correctly. Do you have any idea?
Draggable component code:
import 'package:flame/components.dart';
import 'package:flame/input.dart';
// Zooh bolomjtoi component
class DrawerComponent extends PositionComponent with Draggable {
late final mainRectangle;
Vector2? dragDeltaPosition;
bool get isDragging => dragDeltaPosition != null;
#override
Future<void>? onLoad() async {
final bg = await Sprite.load('drawer.png');
final localSize = Vector2(350, 210);
final mainRectangle = SpriteComponent(size: localSize, sprite: bg);
mainRectangle.position = isDragging ? (dragDeltaPosition)! : Vector2(0, 0);
add(mainRectangle);
}
#override
bool onDragStart(DragStartInfo info) {
print("Drag ehelleee..");
dragDeltaPosition = info.eventPosition.game - position;
return false;
}
#override
bool onDragUpdate(DragUpdateInfo info) {
print("Drag update..");
if (isDragging) {
final localCoords = info.eventPosition.game;
position.setFrom(localCoords - dragDeltaPosition!);
}
return false;
}
#override
bool onDragEnd(DragEndInfo info) {
print("Drag end...");
dragDeltaPosition = null;
return false;
}
#override
bool onDragCancel() {
dragDeltaPosition = null;
return false;
}
}
Main FlameGame class:
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:furniture/drawer.dart';
class Core extends FlameGame with HasDraggables {
late final SpriteComponent mainRectangle;
#override
Future<void>? onLoad() async {
final bg = await Sprite.load('example.jpeg');
final localSize = Vector2(super.size.x * 0.7, super.size.y * 0.6);
final mainRectangle = SpriteComponent(size: localSize, sprite: bg);
mainRectangle.position = Vector2(super.size.x * 0.15, super.size.y * 0.2);
mainRectangle.angle = 0;
add(mainRectangle);
add(DrawerComponent());
}
}
Flutter main class:
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:furniture/core.dart';
void main() {
final game = Core();
runApp(GameWidget(game: game));
}
I think your problem is into your onLoad() because you don't declare the values correctly, I have this example for you:
class Sushi extends SpriteComponent with Draggable, HasGameRef<JapaneseChef>{
/// Sushi constructor
Sushi( this._img, this._position, this._isMove, this._isDraggable,){
position = _position;
size = Vector2(250,250);
}
late final String _img;
late final Vector2 _position;
late Vector2 _dragDeltaPosition;
late final bool _isMove;
late final bool _isDraggable;
/// Get delta position
Vector2 get dragDeltaPosition => _dragDeltaPosition;
set dragDeltaPosition(Vector2? dragDeltaPosition) {
if(dragDeltaPosition != null){
_dragDeltaPosition = dragDeltaPosition;
}
}
#override
Future<void>? onLoad() async{
final spriteSushi = await Sprite.load(_img);
sprite = spriteSushi;
changePriorityWithoutResorting(5);
return super.onLoad();
}
#override
void update(double dt) {
if (_isMove) {
position.x -= 0.6;
if (position.x < -size.x) {
remove(this);
}
}
super.update(dt);
}
#override
bool onDragStart(int pointerId, DragStartInfo info) {
if(_isDraggable) {
dragDeltaPosition = info.eventPosition.game - position;
}
return false;
}
#override
bool onDragCancel(int pointerId) {
dragDeltaPosition = null;
return super.onDragCancel(pointerId);
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo info) {
if (parent is! JapaneseChef) {
return true;
}
final dragDeltaPosition = this.dragDeltaPosition;
position.setFrom(info.eventPosition.game - dragDeltaPosition);
return false;
}
#override
bool onDragEnd(int pointerId, DragEndInfo info) {
dragDeltaPosition = null;
return false;
}
}
Also, you can see the example from Flame engine
Example result
I have two classes.
CustomParentWidget
CustomChildWidget(which shows CircularProgressIndicator if loading and CentralisedAssetLoader id loaded)
Now i need My CustomParentWidget height should be changed after rendering CustomChildWidget..
It is achieved by adding
WidgetsBinding.instance
.addPostFrameCallback((_) => calculateMaxOptionHeight());
in initState of CustomParentWidget..
The problem here is CustomParentWidget is getting height of CircularProgressIndicator only..
Since CustomChildWidget return CircularProgressIndicator at first,
addPostFrameCallBack of CustomParentWidget thinks that ChildWidget has been Rendered and setting the Height to parent..
But i need addPostFrameCallBack to be called again when the CentralisedAssetLoader is also Rendered.
Is there a way to call a function whenever a child widget is rendered?
class CustomParentWidget extends StatefulWidget {
CustomParentWidget();
#override
_CustomParentWidgetState createState() =>
_CustomParentWidgetState();
}
class _CustomParentWidgetState
extends State<CustomParentWidget> {
double widgetHeight;
#override
initState() {
//calling the calculate Function after the Layout is Rendered
WidgetsBinding.instance
.addPostFrameCallback((_) => calculateMaxOptionHeight());
super.initState();
}
void calculateWidgetHeight() {
setState(){
widgetHeight = getWidgetHeight();
}
}
#override
Widget build(BuildContext context) {
return Container(
child: CustomChildWidget(height: widgetHeight),
);
}
}
class CustomChildWidget extends StatefulWidget {
CustomChildWidget({this.height});
#override
_CustomChildWidgetState createState() => _CustomChildWidgetState();
}
class _CustomChildWidgetState extends State<CustomChildWidget> {
double height;
double width;
bool isLoaded;
#override
void initState() {
isLoaded = false;
prepareData();
super.initState();
}
void prepareData() async {
try {
height = getheight();
width = getwidth();
} catch (error) {}
setState(() {
height = height;
width = width;
isLoaded = true;
});
}
#override
Widget build(BuildContext context) {
final screenMaxWidth = MediaQuery.of(context).size.width;
if (!isLoaded) {
return CircularProgressIndicator();
}
return Container(
width: min(screenMaxWidth, width),
height: height,
child: CentralisedAssetLoader(
fit: BoxFit.contain,
assetIdentifier: assetIdentifier,
),
);
}
}
You're really working against the grain of fast performant widget layout. See the basics about layout in https://flutter.dev/docs/development/ui/layout/constraints.
However, if you really don't mind slowing down a bit, you can write very flexible custom layouts with the package:boxy (https://pub.dev/packages/boxy).
I am developing an app using Flutter, where I simply want a rectangle to move on screen when I scroll with my fingers (on Android/iOS) or when I scroll with a mouse wheel or trackpad (on web).
This is what my code looks like:
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
/////////////////
void main()
{
runApp(MyCustomScroller());
}
/////////////////
class MyCustomScroller extends StatefulWidget
{
#override
_MyCustomScrollerState createState() => _MyCustomScrollerState();
}
class _MyCustomScrollerState extends State<MyCustomScroller> with TickerProviderStateMixin
{
AnimationController animController;
double scrollPos = 500;
#override
void initState()
{
super.initState();
animController = AnimationController.unbounded(
vsync: this,
value: 0,
);
animController.addListener(()
{
setState(()
{
scrollPos = animController.value;
});
});
}
#override
void dispose()
{
animController.dispose();
super.dispose();
}
void _onScrollUpdate(final double velPpf)
{
final double velPps = velPpf*60;
Simulation sim = ClampingScrollSimulation(
position: scrollPos,
velocity: velPps,
friction: 0.01,
);
animController.animateWith(sim);
scrollPos += velPpf;
}
#override
Widget build(BuildContext context)
{
return MaterialApp(
title: 'Scrolling Test',
home: Listener(
onPointerMove: (PointerMoveEvent moveEvent) // mobile, web click or web finger (on mobile)
{
_onScrollUpdate(moveEvent.delta.dy);
},
onPointerSignal: (PointerSignalEvent signalEvent) // web scrolling wheel/trackpad
{
if (signalEvent is PointerScrollEvent)
_onScrollUpdate(-signalEvent.scrollDelta.dy);
},
child: Container(
color: Colors.white,
child: CustomPaint(
painter: MyPainter(
pos: scrollPos,
),
child: Container(),
)
)
)
);
}
}
/////////////////
class MyPainter extends CustomPainter
{
final double pos;
MyPainter({
#required this.pos
});
#override
void paint(Canvas canvas, Size size)
{
Paint paint = Paint()
..color = Colors.black
..strokeWidth = 12
..style = PaintingStyle.stroke;
final double x = size.width/2;
final double y = (pos % size.height*1.5) - size.height*0.25;
final Offset offset0 = Offset(x, y);
final Offset offset1 = Offset(x, y+size.height*0.25);
canvas.drawLine(offset0, offset1, paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate)
{
return true;
}
}
Everything seems to work fine, I can see a rectangle that moves up and down as I scroll. When I stop scrolling, the AnimationController continues moving the rectangle. I know similar results can be achieved using a GestureDetector instead of a Listener, but a GestureDetector does not work on mouse scrolling on web.
The problem comes when I run my app in profiling mode: I turn on the Performance Overlay to see if the UI and Raster threads are executing fine and that I don't have any jank.
Most of the time the performance of the raster thread looks fine, as you can see in the following picture:
However sometimes, for some reason, the time taken to render a frame on the Raster thread goes up to around 16-17 ms, as you can see in the following image, and then stays around those values for the upcoming frames, until the animation finishes:
Anybody has any idea why this happens?