感谢您的阅读。我的英语不好,我会尽力解释。我需要在画布中生成反射线,但效果不佳。
我认为我的问题是“计算反射向量的公式”。
之前学的数学和canvas不一样,所以很迷茫
这是我的代码(错误),你可以运行这个(第一行是对的,但是反射是错误的):
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame_forge2d/body_component.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_forge2d/forge2d_game.dart';
import 'package:flutter/material.dart';
import 'component/fixture/fixture_data.dart';
void main() {
runApp(
GameWidget(
game: TestGame(),
),
);
}
class TestGame extends Forge2DGame with MultiTouchDragDetector {
List<Offset> points = [Offset.zero, Offset.zero, Offset.zero];
late var boundaries;
@override
Future<void> onLoad() async {
await super.onLoad();
boundaries = createBoundaries(this);
boundaries.forEach(add);
points[0] = (camera.canvasSize / 2).toOffset();
}
@override
void update(double dt) {
super.update(dt);
}
@override
void render(Canvas canvas) {
super.render(canvas);
canvas.drawLine(points[0], points[1], Paint()..color = Colors.white);
canvas.drawLine(points[1], points[2], Paint()..color = Colors.white);
canvas.drawCircle(points[2], 30, Paint()..color = Colors.white);
}
/// @param [pointStart] start point of line
/// @param [point2] second point of line
/// @param [x] the position x of point need to calculate
/// @return Offset of the point on line
Offset calculateOffsetByX(Offset pointStart, Offset point2, double x) {
//y = ax + b
final a = (pointStart.dy - point2.dy) / (pointStart.dx - point2.dx);
final b = pointStart.dy - a * pointStart.dx;
return Offset(x, a * x + b);
}
/// @param [pointStart] start point of line
/// @param [point2] second point of line
/// @param [y] the position y of point need to calculate
/// @return Offset of the point on line
Offset calculateOffsetByY(Offset pointStart, Offset point2, double y) {
//y = ax + b
final a = (pointStart.dy - point2.dy) / (pointStart.dx - point2.dx);
final b = pointStart.dy - a * pointStart.dx;
return Offset((y - b) / a, y);
}
@override
void onDragUpdate(int pointerId, DragUpdateInfo info) {
var callback = MyRayCastCallBack(this);
var finalPos = getFinalPos(screenToWorld(camera.viewport.effectiveSize) / 2,
info.eventPosition.game);
world.raycast(
callback, screenToWorld(camera.viewport.effectiveSize) / 2, finalPos);
var n = callback.normal;
var i = info.eventPosition.game;
var r = i + (n * (2 * i.dot(n)));
var callback2 = MyRayCastCallBack2(this);
world.raycast(callback2, callback.point, r);
}
Vector2 getFinalPos(Vector2 startPos, Vector2 touchPos) {
return Vector2(
calculateOffsetByY(startPos.toOffset(), touchPos.toOffset(), 0).dx,
calculateOffsetByY(startPos.toOffset(), touchPos.toOffset(), 0).dy);
}
}
class MyRayCastCallBack extends RayCastCallback {
TestGame game;
late Vector2 normal;
late Vector2 point;
MyRayCastCallBack(this.game);
@override
double reportFixture(
Fixture fixture, Vector2 point, Vector2 normal, double fraction) {
game.points[1] = game.worldToScreen(point).toOffset();
this.normal = normal;
this.point = point;
return 0;
}
}
class MyRayCastCallBack2 extends RayCastCallback {
TestGame game;
late Vector2 normal;
late Vector2 point;
MyRayCastCallBack2(this.game);
@override
double reportFixture(
Fixture fixture, Vector2 point, Vector2 normal, double fraction) {
game.points[2] = game.worldToScreen(point).toOffset();
this.normal = normal;
this.point = point;
return 0;
}
}
List<Wall> createBoundaries(Forge2DGame game) {
/*final topLeft = Vector2.zero();
final bottomRight = game.screenToWorld(game.camera.viewport.effectiveSize);
final topRight = Vector2(bottomRight.x, topLeft.y);
final bottomLeft = Vector2(topLeft.x, bottomRight.y);*/
final bottomRight =
game.screenToWorld(game.camera.viewport.effectiveSize) / 8 * 7;
final topLeft = game.screenToWorld(game.camera.viewport.effectiveSize) / 8;
final topRight = Vector2(bottomRight.x, topLeft.y);
final bottomLeft = Vector2(topLeft.x, bottomRight.y);
return [
Wall(topLeft, topRight, FixtureKey.wallTop),
Wall(topRight, bottomRight, FixtureKey.wallRight),
Wall(bottomRight, bottomLeft, FixtureKey.wallBottom),
Wall(bottomLeft, topLeft, FixtureKey.wallLeft),
];
}
class Wall extends BodyComponent {
final Vector2 start;
final Vector2 end;
final FixtureKey fixtureKey;
Wall(this.start, this.end, this.fixtureKey);
@override
Body createBody() {
final shape = EdgeShape()..set(start, end);
final fixtureDef = FixtureDef(shape)
..restitution = 0
..density = 1.0
..friction = 0
..userData = FixtureData(type: FixtureType.wall, key: fixtureKey);
;
final bodyDef = BodyDef()
..userData = this // To be able to determine object in collision
..position = Vector2.zero()
..type = BodyType.static;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}