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: adding custom classes and types #14

Merged
merged 9 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,35 @@ Any other layers will be rendered visually but have no impact on the game automa
additional custom behavior by accessing the layers via `LeapGame.map.tiledMap` and integrating your
own special behavior for tiles or objects.

#### Customizing layer names and classes

Even though the structure explained above should always be followed, the developer can ask Leap
to use different classes, types, names.

In order to do so, a custom `LeapConfiguration` can be passed to the game.

Example:

```dart
class MyLeapGame extend Leap {
MyLeapGame() : super(
configuration: LeapConfiguration(
tiled: const TiledOptions(
groundLayerName: 'Ground',
metadataLayerName: 'Metadata',
playerSpawnClass: 'PlayerSpawn',
hazardClass: 'Hazard',
damageProperty: 'Damage',
platformClass: 'Platform',
slopeType: 'Slope',
slopeRightTopProperty: 'RightTop',
slopeLeftTopProperty: 'LeftTop',
),
),
);
}
```

## Roadmap 🚧

- Improved collision detection API.
Expand All @@ -162,4 +191,4 @@ own special behavior for tiles or objects.
- `melos analyze`
- `melos test`
2. Start your PR title with a [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/)
type (feat:, fix: etc).
type (feat:, fix: etc).
2 changes: 1 addition & 1 deletion examples/standard_platformer/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ packages:
path: "../../packages/leap"
relative: true
source: path
version: "0.1.0"
version: "0.2.0"
material_color_utilities:
dependency: transitive
description:
Expand Down
4 changes: 2 additions & 2 deletions examples/standard_platformer/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ environment:
flutter: 3.13.2

dependencies:
flame: ^1.9.1
flame: ^1.10.0
flame_audio: ^2.1.1
flame_tiled: ^1.14.1
flame_tiled: ^1.15.0
flutter:
sdk: flutter
leap:
Expand Down
1 change: 1 addition & 0 deletions packages/leap/lib/leap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export 'src/entities/entities.dart';
export 'src/input.dart';
export 'src/leap_game.dart';
export 'src/leap_map.dart';
export 'src/leap_options.dart';
export 'src/leap_world.dart';
9 changes: 6 additions & 3 deletions packages/leap/lib/src/leap_game.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import 'package:flame/cache.dart';
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flutter/services.dart';
import 'package:leap/src/entities/entities.dart';
import 'package:leap/src/leap_map.dart';
import 'package:leap/src/leap_world.dart';
import 'package:leap/leap.dart';
import 'package:leap/src/mixins/mixins.dart';

/// A [FlameGame] with all the Leap built-ins.
class LeapGame extends FlameGame with HasTrackedComponents {
LeapGame({
required this.tileSize,
this.appState = AppLifecycleState.resumed,
this.configuration = const LeapConfiguration(),
}) : super(world: LeapWorld(tileSize: tileSize));

final double tileSize;
Expand All @@ -22,6 +21,8 @@ class LeapGame extends FlameGame with HasTrackedComponents {

AppLifecycleState appState;

final LeapConfiguration configuration;

@override
void lifecycleStateChange(AppLifecycleState state) {
super.lifecycleStateChange(state);
Expand All @@ -46,6 +47,7 @@ class LeapGame extends FlameGame with HasTrackedComponents {
String prefix = 'assets/tiles/',
AssetBundle? bundle,
Images? images,
LeapConfiguration configuration = const LeapConfiguration(),
}) async {
camera.world = world;

Expand All @@ -57,6 +59,7 @@ class LeapGame extends FlameGame with HasTrackedComponents {
prefix: prefix,
bundle: bundle,
images: images,
tiledOptions: configuration.tiled,
);

await world.add(leapMap);
Expand Down
63 changes: 46 additions & 17 deletions packages/leap/lib/src/leap_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,28 @@ import 'package:flame/cache.dart';
import 'package:flame/components.dart';
import 'package:flame_tiled/flame_tiled.dart';
import 'package:flutter/services.dart';
import 'package:leap/src/entities/entities.dart';
import 'package:leap/src/leap_game.dart';
import 'package:leap/leap.dart';

/// This component encapsulates the Tiled map, and in particular builds the
/// grid of ground tiles that make up the terrain of the game.
class LeapMap extends PositionComponent with HasGameRef<LeapGame> {
LeapMap({required this.tileSize, required this.tiledMap}) {
groundLayer = getTileLayer<TileLayer>('Ground');
LeapMap({
required this.tileSize,
required this.tiledMap,
this.tiledOptions = const TiledOptions(),
}) {
groundLayer = getTileLayer<TileLayer>(
tiledOptions.groundLayerName,
);

// Size of the map component is based on the tile map's grid.
width = tiledMap.tileMap.map.width * tileSize;
height = tiledMap.tileMap.map.height * tileSize;
}

/// Configuration for the game.
final TiledOptions tiledOptions;

/// Tile size (width and height) in pixels.
final double tileSize;

Expand All @@ -34,6 +42,7 @@ class LeapMap extends PositionComponent with HasGameRef<LeapGame> {
groundTiles = LeapMapGroundTile.generate(
tiledMap.tileMap.map,
groundLayer,
tiledOptions: tiledOptions,
);
add(tiledMap);
for (final column in groundTiles) {
Expand Down Expand Up @@ -63,10 +72,12 @@ class LeapMap extends PositionComponent with HasGameRef<LeapGame> {

/// Spawn location for the player.
Vector2 get playerSpawn {
final metadataLayer = tiledMap.tileMap.getLayer<ObjectGroup>('Metadata');
final metadataLayer = tiledMap.tileMap.getLayer<ObjectGroup>(
tiledOptions.metadataLayerName,
);
if (metadataLayer != null) {
final spawn = metadataLayer.objects.firstWhere(
(obj) => obj.class_ == 'PlayerSpawn',
(obj) => obj.class_ == tiledOptions.playerSpawnClass,
);
return Vector2(spawn.x, spawn.y);
} else {
Expand All @@ -81,6 +92,7 @@ class LeapMap extends PositionComponent with HasGameRef<LeapGame> {
String prefix = 'assets/tiles/',
AssetBundle? bundle,
Images? images,
TiledOptions tiledOptions = const TiledOptions(),
}) async {
final tiledMap = await TiledComponent.load(
tiledMapPath,
Expand All @@ -92,6 +104,7 @@ class LeapMap extends PositionComponent with HasGameRef<LeapGame> {
return LeapMap(
tileSize: tileSize,
tiledMap: tiledMap,
tiledOptions: tiledOptions,
);
}
}
Expand All @@ -102,6 +115,8 @@ class LeapMap extends PositionComponent with HasGameRef<LeapGame> {
/// For the purposes of collision detection, the hitbox is assumed to be the
/// entire tile (except when [isSlope] is `true`).
class LeapMapGroundTile extends PhysicalEntity {
final TiledOptions tiledOptions;

final Tile tile;

/// Coordinates on the tile grid.
Expand All @@ -120,25 +135,33 @@ class LeapMapGroundTile extends PhysicalEntity {
late bool isSlope;

/// Hazards (like spikes) damage on collision.
bool get isHazard => tile.class_ == 'Hazard';
bool get isHazard => tile.class_ == tiledOptions.hazardClass;

/// Platforms only collide from above so the player can jump through them
/// and land on top.
bool get isPlatform => tile.class_ == 'Platform';
bool get isPlatform => tile.class_ == tiledOptions.platformClass;

/// Damage to apply when colliding and [isHazard].
int get hazardDamage {
return tile.properties.getValue<int>('Damage') ?? 0;
final damage = tile.properties.getValue<int>(
tiledOptions.damageProperty,
);
return damage ?? 0;
}

LeapMapGroundTile(
this.tile,
this.gridX,
this.gridY,
) : super(static: true, collisionType: CollisionType.tilemapGround) {
isSlope = tile.type == 'Slope';
rightTop = tile.properties.getValue<int>('RightTop');
leftTop = tile.properties.getValue<int>('LeftTop');
this.gridY, {
this.tiledOptions = const TiledOptions(),
}) : super(static: true, collisionType: CollisionType.tilemapGround) {
isSlope = tile.type == tiledOptions.slopeType;
rightTop = tile.properties.getValue<int>(
tiledOptions.slopeRightTopProperty,
);
leftTop = tile.properties.getValue<int>(
tiledOptions.slopeLeftTopProperty,
);
}

@override
Expand Down Expand Up @@ -181,8 +204,9 @@ class LeapMapGroundTile extends PhysicalEntity {
/// Builds the tile grid full of ground tiles based on [groundLayer].
static List<List<LeapMapGroundTile?>> generate(
TiledMap tileMap,
TileLayer groundLayer,
) {
TileLayer groundLayer, {
TiledOptions tiledOptions = const TiledOptions(),
}) {
final groundTiles = List.generate(
groundLayer.width,
(_) => List<LeapMapGroundTile?>.filled(groundLayer.height, null),
Expand All @@ -195,7 +219,12 @@ class LeapMapGroundTile extends PhysicalEntity {
continue;
}
final tile = tileMap.tileByGid(gid)!;
groundTiles[x][y] = LeapMapGroundTile(tile, x, y);
groundTiles[x][y] = LeapMapGroundTile(
tile,
x,
y,
tiledOptions: tiledOptions,
);
}
}
return groundTiles;
Expand Down
57 changes: 57 additions & 0 deletions packages/leap/lib/src/leap_options.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/// A configurable class that allows the developer to
/// customize different options that Leap will use
/// when reading the map.
class LeapConfiguration {
const LeapConfiguration({
this.tiled = const TiledOptions(),
});

/// The tiled options, change it to configure how Leap
/// interpret the tiled map.
final TiledOptions tiled;
}

/// A configurable class specifically about Tiled names, classes and etc.
class TiledOptions {
const TiledOptions({
this.groundLayerName = 'Ground',
this.metadataLayerName = 'Metadata',
this.playerSpawnClass = 'PlayerSpawn',
this.hazardClass = 'Hazard',
this.damageProperty = 'Damage',
this.platformClass = 'Platform',
this.slopeType = 'Slope',
this.slopeRightTopProperty = 'RightTop',
this.slopeLeftTopProperty = 'LeftTop',
});

/// Which layer name should be used for the player, defaults to "Ground".
final String groundLayerName;

/// Which layer name should be used for the metadata, defaults to "Metadata".
final String metadataLayerName;

/// Which class name should be used for the player spawn point,
/// defaults to "PlayerSpawn".
final String playerSpawnClass;

/// Whick class name represents hazard objects, defaults to "Hazard".
final String hazardClass;

/// Which property name represents damage, defaults to "Damage".
final String damageProperty;

/// Which class name represents platform objects, defaults to "Platform".
final String platformClass;

/// Which property name represents the slope type, defaults to "Slope".
final String slopeType;

/// Which property name represents the slope left bottom, defaults to
/// "RightTop".
final String slopeRightTopProperty;

/// Which property name represents the slope right bottom, defaults to
/// "LeftTop".
final String slopeLeftTopProperty;
}
11 changes: 6 additions & 5 deletions packages/leap/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,12 @@ packages:
flame_behaviors:
dependency: "direct main"
description:
name: flame_behaviors
sha256: e6a7429ed5f16efe7683a63d42f18d6e2c68d6ac3ff0e17f4f62bb224fd294b8
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path: "packages/flame_behaviors"
ref: "feat!(flame_behaviors)-migrate-to-flame-v1.8.0"
resolved-ref: "9409a5d1bb9639beeeac592f615f4346dfb871e5"
url: "https://github.com/VeryGoodOpenSource/flame_behaviors"
source: git
version: "0.3.0"
flame_lint:
dependency: "direct dev"
description:
Expand Down
Loading