I have created a custom paint drawer, which works well, but I liked to create custom brush types like a calligraphy brush, crayon brush, etc...
class DrawingPainter extends CustomPainter {
DrawingPainter({this.pointsList}) : super();
List<DrawingPoints> pointsList;
#override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < pointsList.length - 1; i++) {
if (pointsList[i] != null) {
canvas.saveLayer(Offset.zero & size, Paint());
if (shouldDrawLine(i)) {
canvas.drawLine(pointsList[i].points, pointsList[i + 1].points, pointsList[i].paint);
} else if (shouldDrawPoint(i)) {
canvas.drawPoints(dartUI.PointMode.polygon, [pointsList[i].points,pointsList[i].points], pointsList[i].paint);
}
canvas.restore();
}
}
}
bool shouldDrawPoint(int i) =>
pointsList[i] != null && pointsList.length > i + 1 && pointsList[i + 1] == null;
bool shouldDrawLine(int i) =>
pointsList[i] != null && pointsList.length > i + 1 && pointsList[i + 1] != null;
#override
bool shouldRepaint(DrawingPainter oldDelegate) => true;
}
this is my code for the drawing. How can I modify the brush drawing pattern like those types of brushes?
Related
I have SpriteComponent named Obstacle. I set the priority value to 0 in the super method. But the Obstacle component is regenerated with the update method. It disappears when it exits the screen. When it reoccurs, the priorty value becomes invalid. I am sharing sample screenshots.
first img
second img
The player stays behind the obstacle. GameOverPanel always at the back.
#override
Future<void> onLoad() async {
add(ScreenHitbox());
add(gameRef.homeBackgroundParallaxComponent);
add(gameRef.homeBaseParallax);
add(gameRef.obstacleManager..priority = 0);
add(gameRef.playerManager..priority = 1);
add(gameRef.gameOverPanel..priority = 2);
}
#override
void update(double dt) {
super.update(dt);
gameRef.obstacleManager.updateObstacle(GameConst.gameSpeed * dt);
gameRef.playerManager.changePositionDown(value: GameConst.gravity * dt);
}
Game Over Panel
class GameOverPanel extends Component with HasGameRef<HopyBirdGame> {
GameOverPanel() : super(priority: 4);
#override
Future<void> onLoad() async {
add(GameOverText());
}
#override
void renderTree(Canvas canvas) {
if (gameRef.gameOver) {
super.renderTree(canvas);
}
}
}
class GameOverText extends SpriteComponent with HasGameRef<HopyBirdGame> {
GameOverText() : super(size: Vector2(300, 80), anchor: Anchor.center);
#override
Future<void>? onLoad() async {
sprite = await gameRef.loadSprite(Assets.gameOver.path);
position = Vector2(gameRef.screenWidth / 2, gameRef.screenHeight / 2);
return super.onLoad();
}
}
-Obstacle
class Obstacle extends SpriteComponent
with HasGameRef<HopyBirdGame>, CollisionCallbacks {
final ObstacleType obstacleType;
Obstacle({
required this.obstacleType,
super.position,
super.priority,
}) : super(
size: Vector2(GameConst.obstacleWidth, GameConst.obstacleHeight),
anchor: Anchor.center,
);
Obstacle.empty({this.obstacleType = ObstacleType.empty});
#override
Future<void> onLoad() async {
switch (obstacleType) {
case ObstacleType.up:
sprite = await gameRef.loadSprite(
Assets.redPipeUp.path,
);
break;
case ObstacleType.down:
sprite = await gameRef.loadSprite(
Assets.redPipeDown.path,
);
break;
case ObstacleType.empty:
return;
}
add(RectangleHitbox());
}
}
class Obstacles extends Component with HasGameRef<HopyBirdGame> {
final Obstacle upObstacle;
final Obstacle downObstacle;
bool isCreateNextObstacles = true;
Obstacles({
required this.upObstacle,
required this.downObstacle,
super.priority,
});
#override
Future<void>? onLoad() {
upObstacle.priority = 1;
downObstacle.priority = 1;
createChildren();
return super.onLoad();
}
void createChildren() {
final children = [upObstacle, downObstacle];
addAll(children);
}
}
Obstacle Manager
class ObstacleManager extends Component with HasGameRef<HopyBirdGame> {
ObstacleManager() : super(priority: 1);
ListQueue<Obstacles> history = ListQueue();
#override
Future<void> onLoad() async {
createObstacles();
}
void updateObstacle(double value) {
if (!gameRef.gameOver) {
if (history.isNotEmpty) {
history.last.upObstacle.position.x -= value;
history.last.downObstacle.position.x -= value;
if (history.last.upObstacle.position.x <= gameRef.screenWidth / 2) {
createObstacles();
final isThereAnyObstaclesOutsideScreen = history.any(
(element) =>
element.downObstacle.position.x <=
-(GameConst.obstacleWidth / 2),
);
if (isThereAnyObstaclesOutsideScreen) {
final obstaclesOutsideScreen = history
.lastWhere((element) => element.downObstacle.position.x <= 0);
obstaclesOutsideScreen.removeFromParent();
gameRef.remove(obstaclesOutsideScreen);
}
}
if (history.length >= 2) {
history.elementAt(history.length - 2).upObstacle.position.x -= value;
history.elementAt(history.length - 2).downObstacle.position.x -=
value;
}
}
}
}
void createObstacles() {
final obstaclesGap =
gameRef.screenHeight - gameRef.difficulty.spaceForPlayers;
final gapAboveTheObstacleOnScreen =
((2 * GameConst.obstacleHeight) - obstaclesGap) / 2;
final randomNumber = _randomGenerator(
min: -gameRef.difficulty.distanceAxisYToGoUpAndDown,
max: gameRef.difficulty.distanceAxisYToGoUpAndDown,
);
final axisYOfUpObstacle = (GameConst.obstacleHeight / 2) -
gapAboveTheObstacleOnScreen +
randomNumber;
final axisYOfDownObstacle = axisYOfUpObstacle +
GameConst.obstacleHeight +
gameRef.difficulty.spaceForPlayers;
final obstacles = Obstacles(
upObstacle: Obstacle(
obstacleType: ObstacleType.up,
position: Vector2(
gameRef.screenWidth + (GameConst.obstacleWidth / 2),
axisYOfUpObstacle,
),
),
downObstacle: Obstacle(
obstacleType: ObstacleType.down,
position: Vector2(
gameRef.screenWidth + (GameConst.obstacleWidth / 2),
axisYOfDownObstacle,
),
),
);
history.add(obstacles);
gameRef.add(obstacles);
}
double _randomGenerator({required double min, required double max}) {
final gap = (max - min).toInt();
return min + Random().nextInt(gap);
}
}
EDIT: The same problem applies in game over panel.
Game Over Panel
class GameOverPanel extends Component with HasGameRef<HopyBirdGame> {
GameOverPanel() : super();
#override
Future<void> onLoad() async {
add(GameOverText());
}
#override
void renderTree(Canvas canvas) {
if (gameRef.gameOver) {
super.renderTree(canvas);
}
}
}
class GameOverText extends SpriteComponent with HasGameRef<HopyBirdGame> {
GameOverText()
: super(
size: Vector2(300, 80),
anchor: Anchor.center,
);
#override
Future<void>? onLoad() async {
sprite = await gameRef.loadSprite(Assets.gameOver.path);
position = Vector2(gameRef.screenWidth / 2, gameRef.screenHeight / 2);
return super.onLoad();
}
}
Similarly, the first assignment is made in the Flame Game class.
I'm guessing (since the code for the ObstacleManager isn't present) that you are adding the obstacles directly to the game from the ObstacleManager to the component tree and that you aren't adding the priority to the actual Obstacle components.
If this is not the case, please update the question with the code for the ObstacleManager.
EDIT: After code upload.
It doesn't help that you are giving priorities to the manager classes when the components are not added as children to them, but to the gameRef. Since the player manager class isn't included in the question you either have to set the Obstacles to priority -1, or you have to give the player priority 1 (and obstacles will default to 0).
gameRef.add(obstacles..priority = -1);
This will make the obstacles be behind the background, so you have to also change the background parallaxes:
add(gameRef.homeBackgroundParallaxComponent..priority = -3);
add(gameRef.homeBaseParallax..priority = -2);
So it will be better to just set the player priority to 1 where you are adding that one to the game, because then you don't have to change all the other classes.
I am developing a flutter application. In that am using Paint to draw lines. In free hand line the point header is correctly displaying when we draw a straight line. But when we rotate the line, the point header position got misplaced.
case PaintMode.freeStyleArrow:
for (var i = 0; i < _offset!.length - 1; i++) {
if (_offset[i] != null && _offset[i + 1] != null) {
final _path = Path()
..moveTo(_offset[i]!.dx, _offset[i]!.dy)
..lineTo(_offset[i + 1]!.dx, _offset[i + 1]!.dy);
canvas.drawPath(_path, _painter!..strokeCap = StrokeCap.round);
paintsFreestyleArrow(canvas,_offset[0]!, _offset[_offset.length - 2]!, _painter, size);
}
else if (_offset[i] != null && _offset[i + 1] == null) {
canvas.drawPoints(PointMode.points, [_offset[i]!],
_painter!);
}}
break;
i am working on a canvas drawing module in to it i need to erase user drawing
basic funda is
adding image in canvas
user can draw on image using pencil (i.e black color) now user can erase this black color on erase function (i.e clear user drawing )
my try is :
case PaintMode.eraser:
print('eraser**** _image Painter!!!*'); // print(_painter.color)
// canvas.saveLayer(Offset.zero & size, Paint());1
var _painterTemp = _painter!
// ..color = Colors.transparent.withOpacity(0.8)//also tried it
..strokeCap = StrokeCap.round
..blendMode = BlendMode.clear;
for (var i = 0; i < _offset!.length - 1; i++) {
if (_offset[i] != null && _offset[i + 1] != null) {
final _path = Path()
..moveTo(_offset[i]!.dx, _offset[i]!.dy)
..lineTo(_offset[i + 1]!.dx, _offset[i + 1]!.dy);
} else if (_offset[i] != null && _offset[i + 1] == null) {
canvas.drawPoints(PointMode.points, [_offset[i]!], _painterTemp);
}
}
// canvas.restore();//1
break
but i am getting black lines only
took reference from
https://github.com/yellowQ-software/yellowQ-Flutter-Image-Painter
edit-----
i've edited like
case PaintMode.eraser:
print('eraser**** _image Painter!!!*');
var _painterTemp = _painter!
..color = Colors.transparent
..blendMode = BlendMode.clear; //srcOver
for (var i = 0; i < _offset!.length - 1; i++) {
if (_offset[i] != null && _offset[i + 1] != null) {
final _path = Path()
..moveTo(_offset[i]!.dx, _offset[i]!.dy)
..lineTo(_offset[i + 1]!.dx, _offset[i + 1]!.dy);
canvas.drawPath(_path, _painter);
canvas.drawPath(_path, _painterTemp);
canvas.saveLayer(Offset.zero & size, Paint());
} else if (_offset[i] != null && _offset[i + 1] == null) {
canvas.drawPoints(PointMode.points, [_offset[i]!], _painter);
canvas.drawPoints(PointMode.points, [_offset[i]!], _painterTemp);
}
// canvas.saveLayer(Offset.zero & size, Paint()); //1
}
// canvas.restore();//1
break;
but not working but getting custom painter called canvas.save() or canvas.saveLayer() at least 773 more times than it called canvas.restore().
any help?
I am making a game in flutter, and i found this link in github https://github.com/g0rdan/Flutter.Bird and i tried to run it in my computer and i encounter this error error: 'ComposedComponent' can't be mixed onto 'PositionComponent' because 'PositionComponent' doesn't implement 'HasGameRef'. (mixin_application_not_implemented_interface at [myfirstgame] lib\game\bird.dart:16)
enum BirdStatus { waiting, flying}
enum BirdFlyingStatus { up, down, none }
class Bird extends PositionComponent with ComposedComponent { == from this line
int _counter = 0;
int _movingUpSteps = 15;
Size _screenSize;
double _heightDiff = 0.0;
double _stepDiff = 0.0;
BirdGround ground;
BirdStatus status = BirdStatus.waiting;
BirdFlyingStatus flyingStatus = BirdFlyingStatus.none;
Bird(Image spriteImage, Size screenSize)
{
_screenSize = screenSize;
List<Sprite> sprites = [
Sprite.fromImage(
spriteImage,
width: SpriteDimensions.birdWidth,
height: SpriteDimensions.birdHeight,
y: SpritesPostions.birdSprite1Y,
x: SpritesPostions.birdSprite1X,
),
Sprite.fromImage(
spriteImage,
width: SpriteDimensions.birdWidth,
height: SpriteDimensions.birdHeight,
y: SpritesPostions.birdSprite2Y,
x: SpritesPostions.birdSprite2X,
),
Sprite.fromImage(
spriteImage,
width: SpriteDimensions.birdWidth,
height: SpriteDimensions.birdHeight,
y: SpritesPostions.birdSprite3Y,
x: SpritesPostions.birdSprite3X,
)
];
var animatedBird = new Animation.spriteList(sprites, stepTime: 0.15);
this.ground = BirdGround(animatedBird);
this..add(ground);
}
void setPosition(double x, double y) {
this.ground.x = x;
this.ground.y = y;
}
void update(double t) {
if (status == BirdStatus.flying) {
_counter++;
if (_counter <= _movingUpSteps) {
flyingStatus = BirdFlyingStatus.up;
this.ground.showAnimation = true;
this.ground.angle -= 0.01;
this.ground.y -= t * 100 * getSpeedRatio(flyingStatus, _counter);
}
else {
flyingStatus = BirdFlyingStatus.down;
this.ground.showAnimation = false;
if (_heightDiff == 0)
_heightDiff = (_screenSize.height - this.ground.y);
if (_stepDiff == 0)
_stepDiff = this.ground.angle.abs() / (_heightDiff / 10);
this.ground.angle += _stepDiff;
this.ground.y += t * 100 * getSpeedRatio(flyingStatus, _counter);
}
this.ground.update(t);
}
}
double getSpeedRatio(BirdFlyingStatus flyingStatus, int counter){
if (flyingStatus == BirdFlyingStatus.up) {
var backwardCounter = _movingUpSteps - counter;
return backwardCounter / 10.0;
}
if (flyingStatus == BirdFlyingStatus.down) {
var diffCounter = counter - _movingUpSteps;
return diffCounter / 10.0;
}
return 0.0;
}
void jump() {
Flame.audio.play('wing.wav');
status = BirdStatus.flying;
_counter = 0;
this.ground.angle = 0;
}
}
class BirdGround extends AnimationComponent {
bool showAnimation = true;
BirdGround(Animation animation)
: super(ComponentDimensions.birdWidth, ComponentDimensions.birdHeight, animation);
#override
void update(double t){
if (showAnimation) {
super.update(t);
}
}
}
This uses a very old Flame version, so I would recommend not building anything on top of it.
But to your problem, it is missing the HasGameRef mixin on your component, so if you write something like this it should work:
class Bird extends PositionComponent with HasGameRef<YourGameClass>, ComposedComponent { ...
I'm trying to process the camera image input in Flutter but I can't seem to get it to work.
I have a listener on the camera feed that launch a function that is supposed to process the images btu everytime I end up doing anything in the function the program interface freeze. My guess is that I have too many frames to process and thus the program freezes but I have no idea how to ignore old frames.
Here is my code so far
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:image/image.dart' as imglib;
import 'package:flutter/scheduler.dart';
import 'user_data_container.dart';
class Camera extends StatefulWidget {
Camera();
#override
_CameraState createState() => new _CameraState();
}
class _CameraState extends State<Camera> {
CameraController controller;
bool isDetecting = false;
double redavg;
imglib.Image last_image;
int count = 0;
Image _image_display;
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
_initializeApp();
});
}
void _initializeApp() async {
var cameras = UserDataContainer.of(context).data.cameras;
if (cameras == null || cameras.length < 1) {
print('No camera is found');
} else {
controller = new CameraController(
cameras[0],
ResolutionPreset.high,
);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
controller.startImageStream((CameraImage img) async {
print(count.toString() + "Stream. detecting: " + isDetecting.toString());
if (!isDetecting) {
isDetecting = true;
int startTime = new DateTime.now().millisecondsSinceEpoch;
_processCameraImage(img);
// int endTime = new DateTime.now().millisecondsSinceEpoch;
// print("Detection done in " + (endTime - startTime).toString());
// isDetecting = false;
}
else{
print("It's detecting");
}
});
});
}
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (controller == null || !controller.value.isInitialized) {
return Container();
}
return
Scaffold(
body: Column(
children: <Widget>[
Text("red: "+ redavg.toString() + " "+ count.toString()),
Expanded(child: last_image == null ? Container() : _image_display),
],
),
);
// );
}
void _processCameraImage(CameraImage image) async {
count = count +1;
print("p: " + image.planes.length.toString());
// if (isDetecting) {
// print("Already detecting;");
// return;
// }
// else{
// isDetecting = true;
try {
await processFrame(image);
} catch (e) {
// await handleExepction(e)
} finally {
print("Done detecting :)");
// isDetecting = false;
}
// }
}
void processFrame(CameraImage image) async {
print ("convert");
imglib.Image convertedImage = await _convertCameraImage(image);
last_image = convertedImage;
imglib.PngEncoder pngEncoder = new imglib.PngEncoder(level: 0, filter: 0);
// Convert to png
List<int> png = pngEncoder.encodeImage(last_image);
_image_display = Image.memory(png);
// var colors = colorAverage(convertedImage);
setState(() {
// redavg = colors[2];
// print(colors.toString());
});
}
imglib.Image _convertCameraImage(CameraImage image) {
int width = image.width;
int height = image.height;
var img = imglib.Image(image.planes[0].bytesPerRow, height); // Create Image buffer
const int hexFF = 0xFF000000;
final int uvyButtonStride = image.planes[1].bytesPerRow;
final int uvPixelStride = image.planes[1].bytesPerPixel;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int uvIndex =
uvPixelStride * (x / 2).floor() + uvyButtonStride * (y / 2).floor();
final int index = y * width + x;
final yp = image.planes[0].bytes[index];
final up = image.planes[1].bytes[uvIndex];
final vp = image.planes[2].bytes[uvIndex];
// Calculate pixel color
int r = (yp + vp * 1436 / 1024 - 179).round().clamp(0, 255);
int g = (yp - up * 46549 / 131072 + 44 - vp * 93604 / 131072 + 91)
.round()
.clamp(0, 255);
int b = (yp + up * 1814 / 1024 - 227).round().clamp(0, 255);
// color: 0x FF FF FF FF
// A B G R
img.data[index] = hexFF | (b << 16) | (g << 8) | r;
}
}
// Rotate 90 degrees to upright
// var img1 = imglib.copyRotate(img, 90);
imglib.PngEncoder pngEncoder = new imglib.PngEncoder(level: 0, filter: 0);
// Convert to png
List<int> png = pngEncoder.encodeImage(img);
_image_display = Image.memory(png);
return img;
}
}