- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
感谢您的阅读。我的英语不好,我会尽可能地解释这个。我需要在 Canvas 中生成反射线,但效果不佳。
我认为我的问题是“计算反射矢量的公式”。
之前学的数学和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);
}
}
最佳答案
您的代码中有几处错误。但是您的猜测是正确的,反射(reflect)关于法线的光线转换的数学是错误的。更准确地说,您用作第一个光线转换的矢量似乎是错误的。
代替,
var i = info.eventPosition.game;
应该是这样的
var i = callback.point - (screenToWorld(camera.viewport.effectiveSize) / 2);
基本上,它应该是一个从您的原始起点开始并指向命中点的相对向量。希望这能解决您的问题。
这里还有一些在您的代码中看起来不对的地方
多个回调类:您无需为捕获多个光线转换定义多个回调类。您可以使用同一类的多个对象。如果你真的想推送它,你甚至可以根据你的用例一次又一次地使用同一个对象。
返回自 reportFixture()
: 我看到你从这个方法返回 0。在您的简单情况下,这可能会正常工作,但返回 0 意味着您希望光线转换在它遇到的第一个固定装置处停止。不幸的是, world.raycast
does not report fixtures in any fixed order .所以如果沿射线有多个固定装置,reportFixture
可能会要求最远的固定装置。如果你真的想得到最近的灯具,你应该返回 fraction
参数作为返回值。
我在这里发布了一个示例代码,它可以根据 nBounces
向您报告多次点击。参数。
void newRaycast(Vector2 start, Vector2 end, int nBounces) {
if (nBounces > 0) {
final callback = NearestRayCastCallback();
world.raycast(callback, start, end);
// Make sure that we got a hit.
if (callback.nearestPoint != null && callback.normalAtInter != null) {
// Store the hit location for rendering later on.
points.add(worldToScreen(callback.nearestPoint!.clone()));
// Figure out the current ray direction and then reflect it
// about the collision normal.
Vector2 originalDirection =
(callback.nearestPoint! - start).normalized();
final dotProduct = callback.normalAtInter!.dot(originalDirection);
final newDirection =
originalDirection - callback.normalAtInter!.scaled(2 * dotProduct);
// Call newRayCast with new start and end points. New end is just a point 500
// units along the new direction.
newRaycast(
callback.nearestPoint!.clone(), newDirection.scaled(500), --nBounces);
}
}
}
这是我的回调类的定义。
class NearestRayCastCallback extends RayCastCallback {
Vector2? nearestPoint;
Vector2? normalAtInter;
@override
double reportFixture(
Fixture fixture, Vector2 point, Vector2 normal, double fraction) {
nearestPoint = point;
normalAtInter = normal;
return fraction;
}
}
在上面的代码中,points
是final points = List<Vector2>.empty(growable: true);
这就是我从这些点渲染线条的方式:
for (int i = 0; i < points.length - 1; ++i) {
canvas.drawLine(points[i].toOffset(), points[i + 1].toOffset(),
Paint()..color = Colors.black..strokeWidth = 2);
}
关于 flutter 火焰 : How to calculate the relect of a raycast?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70381597/
感谢您的阅读。我的英语不好,我会尽可能地解释这个。我需要在 Canvas 中生成反射线,但效果不佳。 我认为我的问题是“计算反射矢量的公式”。 之前学的数学和canvas不一样,所以很迷茫 这是我的代
我正在尝试使用动态创建的结构来解析 JSON 文件,但显然我做错了什么。有人可以告诉我们我在这里做错了什么: structured := make(map[string][]reflect.Struc
我是一名优秀的程序员,十分优秀!