Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add lookAt method for PositionComponent #1891

Merged
merged 33 commits into from
Sep 18, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
75c324e
Add lookAt method
ufrshubham Sep 6, 2022
a4287c9
Add test for lookAt
ufrshubham Sep 6, 2022
d269b52
Add angularOffset
ufrshubham Sep 6, 2022
39e3f83
Replace angularOffset with nativeAngle
ufrshubham Sep 10, 2022
fdc1985
Merge branch 'main' into feat/lookAt
ufrshubham Sep 10, 2022
609f239
Add lookAt tests with nativeAngle
ufrshubham Sep 10, 2022
3d05af8
Merge branch 'main' into feat/lookAt
ufrshubham Sep 10, 2022
8ba397c
Resolve merge conflicts
ufrshubham Sep 10, 2022
d2d3048
Add nativeAngle as optional parameter
ufrshubham Sep 10, 2022
f48b3a3
Remove _nativeDirection
ufrshubham Sep 10, 2022
7f65989
Add angleTo
ufrshubham Sep 11, 2022
02eb465
Add corner case for lookAt
ufrshubham Sep 11, 2022
e1ad4ea
Revert "Add nativeAngle as optional parameter"
ufrshubham Sep 11, 2022
d8c500e
Add nativeAngle as input for sprite components
ufrshubham Sep 11, 2022
e26083e
Merge branch 'main' into feat/lookAt
ufrshubham Sep 11, 2022
edc4948
Consider absoluteAngle in angleTo calculations
ufrshubham Sep 11, 2022
ab218d8
Add lookAt test for nested components
ufrshubham Sep 11, 2022
08957d8
Update comments with csys for target
ufrshubham Sep 12, 2022
c9d7e2f
Auto-format components.md
ufrshubham Sep 13, 2022
01a2173
Add nativeAngle docs
ufrshubham Sep 13, 2022
b5e3509
Add lookAt and angleTo examples
ufrshubham Sep 13, 2022
2870f4d
Fixed codelink
ufrshubham Sep 13, 2022
4df5648
Merge branch 'main' into feat/lookAt
ufrshubham Sep 13, 2022
ec53148
Revert auto-format changes
ufrshubham Sep 13, 2022
f213ec3
Fix grammar in example description
ufrshubham Sep 13, 2022
7d75fdd
Rename comp to component
ufrshubham Sep 13, 2022
48bbed3
Return delta angle from angleTo
ufrshubham Sep 13, 2022
91ff297
Update expected values for angleTo tests
ufrshubham Sep 13, 2022
499eef0
Use RotateEffect.by instead of RotateEffect.to
ufrshubham Sep 13, 2022
09fdc45
Merge branch 'main' into feat/lookAt
ufrshubham Sep 13, 2022
1863a15
Merge branch 'main' into feat/lookAt
ufrshubham Sep 17, 2022
2a9de0c
Merge branch 'main' into feat/lookAt
ufrshubham Sep 18, 2022
51266f6
Merge branch 'main' into feat/lookAt
ufrshubham Sep 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 31 additions & 43 deletions doc/flame/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

This diagram might look intimidating, but don't worry, it is not as complex as it looks.


ufrshubham marked this conversation as resolved.
Show resolved Hide resolved
## Component

All components inherit from the abstract class `Component` and all components can have other
Expand All @@ -27,8 +26,7 @@ void main() {
The `Component()` here could of course be any subclass of `Component`.

Every `Component` has a few methods that you can optionally implement, which are used by the
`FlameGame` class.

ufrshubham marked this conversation as resolved.
Show resolved Hide resolved
`FlameGame` class.

### Component lifecycle

Expand All @@ -54,11 +52,10 @@ on the rest of the game engine).

A component lifecycle state can be checked by a series of getters:

- `isLoaded`: Returns a bool with the current loaded state
- `loaded`: Returns a future that will complete once the component has finished loading
- `isMounted`: Returns a bool with the current mounted state
- `mounted`: Returns a future that will complete once the component has finished mounting

- `isLoaded`: Returns a bool with the current loaded state
- `loaded`: Returns a future that will complete once the component has finished loading
- `isMounted`: Returns a bool with the current mounted state
- `mounted`: Returns a future that will complete once the component has finished mounting
ufrshubham marked this conversation as resolved.
Show resolved Hide resolved

### Priority

Expand Down Expand Up @@ -106,7 +103,6 @@ class MyComponent extends PositionComponent with Tappable {
In the example above we first initialize the component with priority 1, and then when the user taps
the component we change the priority to 2.


### Composability of components

Sometimes it is useful to wrap other components inside of your component. For example by grouping
Expand Down Expand Up @@ -150,6 +146,7 @@ children during the course of the game.

The second method is to use the `children:` parameter in the component's
constructor. This approach more closely resembles the standard Flutter API:

```dart
class MyGame extends FlameGame {
@override
Expand Down Expand Up @@ -177,7 +174,6 @@ available eventually: after they are loaded and mounted. We can only assure
that they will appear in the children list in the same order as they were
scheduled for addition.


### Ensuring a component has a given parent

When a component requires to be added to a specific parent type the
Expand All @@ -198,10 +194,9 @@ class MyComponent extends Component with ParentIsA<MyParentComponent> {
If you try to add `MyComponent` to a parent that is not `MyParentComponent`,
an assertion error will be thrown.


### Ensuring a component has a given ancestor

When a component requires to have a specific ancestor type somewhere in the
When a component requires to have a specific ancestor type somewhere in the
component tree, `HasAncestor` mixin can be used to enforce that relationship.

The mixin exposes the `ancestor` field that will be of the given type.
Expand All @@ -221,7 +216,6 @@ class MyComponent extends Component with HasAncestor<MyAncestorComponent> {
If you try to add `MyComponent` to a tree that does not contain `MyAncestorComponent`,
an assertion error will be thrown.


### Querying child components

The children that have been added to a component live in a `QueryableOrderedSet` called
Expand Down Expand Up @@ -252,7 +246,6 @@ void update(double dt) {
}
```


### Querying components at a specific point on the screen

The method `componentsAtPoint()` allows you to check which components were rendered at some point
Expand All @@ -269,6 +262,7 @@ implementation. However, if you're defining a custom class that derives from `Co
to implement the `containsLocalPoint()` method yourself.

Here is an example of how `componentsAtPoint()` can be used:

```dart
void onDragUpdate(DragUpdateInfo info) {
game.componentsAtPoint(info.widget).forEach((component) {
Expand All @@ -279,17 +273,17 @@ void onDragUpdate(DragUpdateInfo info) {
}
```


### PositionType

If you want to create a HUD (Head-up display) or another component that isn't positioned in relation
to the game coordinates, you can change the `PositionType` of the component.
The default `PositionType` is `positionType = PositionType.game` and that can be changed to
either `PositionType.viewport` or `PositionType.widget` depending on how you want to position
the component.

- `PositionType.game` (Default) - Respects camera and viewport.
- `PositionType.viewport` - Respects viewport only (ignores camera).
- `PositionType.widget` - Position in relation to the coordinate system of the Flutter game
- `PositionType.game` (Default) - Respects camera and viewport.
- `PositionType.viewport` - Respects viewport only (ignores camera).
- `PositionType.widget` - Position in relation to the coordinate system of the Flutter game
widget (i.e. the raw canvas).

Most of your components will probably be positioned according to `PositionType.game`, since you
Expand All @@ -303,7 +297,6 @@ the viewport.
Do note that this setting is only respected if the component is added directly to the root
`FlameGame` and not as a child component of another component.


## PositionComponent

This class represent a positioned object on the screen, being a floating rectangle or a rotating
Expand All @@ -312,31 +305,41 @@ sprite. It can also represent a group of positioned components if children are a
The base of the `PositionComponent` is that it has a `position`, `size`, `scale`, `angle` and
`anchor` which transforms how the component is rendered.


### Position

The `position` is just a `Vector2` which represents the position of the component's anchor in
relation to its parent; if the parent is a `FlameGame`, it is in relation to the viewport.


### Size

The `size` of the component when the zoom level of the camera is 1.0 (no zoom, default).
The `size` is *not* in relation to the parent of the component.


### Scale

The `scale` is how much the component and its children should be scaled. Since it is represented
by a `Vector2`, you can scale in a uniform way by changing `x` and `y` with the same amount, or in a
non-uniform way, by change `x` or `y` by different amounts.


### Angle

The `angle` is the rotation angle around the anchor, represented as a double in radians. It is
relative to the parent's angle.

### Native Angle
ufrshubham marked this conversation as resolved.
Show resolved Hide resolved

The `nativeAngle` is an angle in radians, measured clockwise, representing the default orientation of the component. It can be used to define the direction in which the component is facing when [angle](#angle) is zero.

It is specially helpful when making a sprite based component look at a specific target. If the original image of the sprite is not facing in the up/north direction, the calculated angle to make the component look at the target will need some offset to make it look correct. For such cases, `nativeAngle` can be used to let the component know what direction the original image is faces.

An example could be a bullet image pointing in east direction. In this case `nativeAngle` can be set to pi/2 radians. Following are some common directions and their correspondin native angle values.

Direction | Native Angle | In degrees
----------|--------------|-------------
Up/North | 0 | 0
Down/South| pi or -pi | 180 or -180
Left/West | -pi/2 | -90
Right/East| pi/2 | 90

### Anchor

Expand All @@ -346,7 +349,6 @@ position on the screen will be in the center of the component and if an `angle`
rotated around the anchor, so in this case around the center of the component. You can think of it
as the point within the component by which Flame "grabs" it.


### PositionComponent children

All children of the `PositionComponent` will be transformed in relation to the parent, which means
Expand All @@ -369,7 +371,6 @@ Future<void> onLoad() async {
Remember that most components that are rendered on the screen are `PositionComponent`s, so
this pattern can be used in for example [](#spritecomponent) and [](#spriteanimationcomponent) too.


### Render PositionComponent

When implementing the `render` method for a component that extends `PositionComponent` remember to
Expand All @@ -389,7 +390,6 @@ In the event that you want to change the direction of your components rendering,
In case you want to flip a component around its center without having to change the anchor to
`Anchor.center`, you can use `flipHorizontallyAroundCenter()` and `flipVerticallyAroundCenter()`.


## SpriteComponent

The most commonly used implementation of `PositionComponent` is `SpriteComponent`, and it can be
Expand All @@ -415,7 +415,6 @@ class MyGame extends FlameGame {
}
```


## SpriteAnimationComponent

This class is used to represent a Component that has sprites that run in a single cyclic animation.
Expand Down Expand Up @@ -528,7 +527,6 @@ final robot = SpriteAnimationGroupComponent<RobotState>(
robot.current = RobotState.running;
```


## SpriteGroup

`SpriteGroupComponent` is pretty similar to its animation counterpart, but especially for sprites.
Expand All @@ -555,7 +553,6 @@ class ButtonComponent extends SpriteGroupComponent<ButtonState>
}
```


## SvgComponent

**Note**: To use SVG with Flame, use the [`flame_svg`](https://github.com/flame-engine/flame_svg)
Expand All @@ -573,7 +570,6 @@ final android = SvgComponent.fromSvg(
);
```


## FlareActorComponent

**Note**: The previous implementation of a Flare integration API using `FlareAnimation` and
Expand Down Expand Up @@ -632,7 +628,6 @@ You can also change the current playing animation by using the `updateAnimation`
For a working example, check the example in the
[flame_flare repository](https://github.com/flame-engine/flame/tree/main/packages/flame_flare/example).


## ParallaxComponent

This `Component` can be used to render backgrounds with a depth feeling by drawing several
Expand Down Expand Up @@ -710,6 +705,7 @@ behavior, for example if you are not making a side-scrolling game, you can set t
you then pass in to the `ParallaxComponent`'s constructor.

Advanced example:

```dart
final images = [
loadParallaxImage('stars.jpg', repeat: ImageRepeat.repeat, alignment: Alignment.center, fill: LayerFill.width),
Expand All @@ -725,11 +721,11 @@ final parallaxComponent = ParallaxComponent.fromParallax(
);
```

- The stars image in this example will be repeatedly drawn in both axis, align in the center and be
- The stars image in this example will be repeatedly drawn in both axis, align in the center and be
scaled to fill the screen width.
- The planets image will be repeated in Y-axis, aligned to the bottom left of the screen and not be
- The planets image will be repeated in Y-axis, aligned to the bottom left of the screen and not be
scaled.
- The dust image will be repeated in X-axis, aligned to the top right and scaled to fill the screen
- The dust image will be repeated in X-axis, aligned to the top right and scaled to fill the screen
height.

Once you are done setting up your `ParallaxComponent`, add it to the game like with any other
Expand All @@ -752,7 +748,6 @@ It is also possible to create custom renderers by extending the `ParallaxRendere
Three example implementations can be found in the
[examples directory](https://github.com/flame-engine/flame/tree/main/examples/lib/stories/parallax).


## ShapeComponents

A `ShapeComponent` is the base class for representing a scalable geometrical shape. The shapes have
Expand All @@ -763,14 +758,14 @@ These shapes are meant as a tool for using geometrical shapes in a more general
with the collision detection system, where you want to use the
[ShapeHitbox](collision_detection.md#shapehitbox)es.


### PolygonComponent

A `PolygonComponent` is created by giving it a list of points in the constructor, called vertices.
This list will be transformed into a polygon with a size, which can still be scaled and rotated.

For example, this would create a square going from (50, 50) to (100, 100), with it's center in
(75, 75):

```dart
void main() {
PolygonComponent([
Expand Down Expand Up @@ -814,7 +809,6 @@ arrows.
Remember to define the lists in a counter clockwise manner (if you think in the screen coordinate
system where the y-axis is flipped, otherwise it is clockwise).


### RectangleComponent

A `RectangleComponent` is created very similarly to how a `PositionComponent` is created, since it
Expand Down Expand Up @@ -881,7 +875,6 @@ void main() {
}
```


### CircleComponent

If you know how long your circle's position and/or how long the radius is going to be from the start
Expand All @@ -908,7 +901,6 @@ void main() {
}
```


## TiledComponent

Currently we have a very basic implementation of a Tiled component. This API uses the lib
Expand All @@ -918,7 +910,6 @@ layers.
An example of how to use the API can be found
[here](https://github.com/flame-engine/flame_tiled/tree/main/example).


## IsometricTileMapComponent

This component allows you to render an isometric map based on a cartesian matrix of blocks and an
Expand Down Expand Up @@ -955,7 +946,6 @@ selector. The code can be found
[here](https://github.com/flame-engine/flame/blob/main/examples/lib/stories/rendering/isometric_tile_map_example.dart),
and a live version can be seen [here](https://examples.flame-engine.org/#/Rendering_Isometric%20Tile%20Map).


## NineTileBoxComponent

A Nine Tile Box is a rectangle drawn using a grid sprite.
Expand All @@ -973,7 +963,6 @@ Check the example app
[nine_tile_box](https://github.com/flame-engine/flame/blob/main/examples/lib/stories/rendering/nine_tile_box_example.dart)
for details on how to use it.


## CustomPainterComponent

A `CustomPainter` is a Flutter class used with the `CustomPaint` widget to render custom
Expand All @@ -989,7 +978,6 @@ Check the example app
[custom_painter_component](https://github.com/flame-engine/flame/blob/main/examples/lib/stories/widgets/custom_painter_example.dart)
for details on how to use it.


## Effects

Flame provides a set of effects that can be applied to a certain type of components, these effects
Expand Down
14 changes: 14 additions & 0 deletions examples/lib/stories/components/components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import 'package:examples/commons/commons.dart';
import 'package:examples/stories/components/composability_example.dart';
import 'package:examples/stories/components/debug_example.dart';
import 'package:examples/stories/components/game_in_game_example.dart';
import 'package:examples/stories/components/look_at_example.dart';
import 'package:examples/stories/components/look_at_smooth_example.dart';
import 'package:examples/stories/components/priority_example.dart';
import 'package:flame/game.dart';

Expand Down Expand Up @@ -31,5 +33,17 @@ void addComponentsStories(Dashbook dashbook) {
(_) => GameWidget(game: GameInGameExample()),
codeLink: baseLink('components/game_in_game_example.dart'),
info: GameInGameExample.description,
)
..add(
'Look At',
(_) => GameWidget(game: LookAtExample()),
codeLink: baseLink('components/look_at_example.dart'),
info: LookAtExample.description,
)
..add(
'Look At Smooth',
(_) => GameWidget(game: LookAtSmoothExample()),
codeLink: baseLink('components/look_at_smooth_example.dart'),
info: LookAtExample.description,
);
}
Loading