このページではFlmaeを使って、キーボード操作でキャラクターを左右に移動させる方法を紹介します。
ゲーム画面を作成
まずは何もない空のゲーム画面を作成します。
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
void main() {
final game = SampleGame();
runApp(
GameWidget(game: game)
);
}
class SampleGame extends FlameGame {
}
キャラクターの配置
プロジェクトにassets/images
フォルダを作成し、そこに画像を設置します。
今回はいらすとやからサッカーボールの画像をお借りしました。
ファイル名は何でも良いですが、今回は「ball」としておきました。
画像の読み込みができるようにpubspec.yamlにも以下のように追記しておきます。
assets:
- assets/images/
画像ができたら、Flameで背景画像を設定する方法で紹介したやり方でサッカーボールを画面に追加します。
import 'package:flame/components.dart'; // 追加
import 'package:flame/flame.dart'; // 追加
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
void main() {
final game = SampleGame();
runApp(
GameWidget(game: game)
);
}
class SampleGame extends FlameGame {
// 追加
@override
Future<void> onLoad() async {
add(Ball());
}
}
// 追加
class Ball extends SpriteComponent with HasGameRef<SampleGame>{
@override
Future<void> onLoad() async {
// 画像の読み込み
final ball = await Flame.images.load("ball.png");
// ボールのサイズ
size = Vector2(100, 100);
// 画面のサイズを取得
final screenHeight = gameRef.size.y;
// ボールの配置位置を左下に配置(Y座標:画面の高さ - ボールのサイズの高さ - 20)
position = Vector2(50, screenHeight - size.y - 20);
sprite = Sprite(ball);
}
}
実行すると画面の左下にサッカーボールが配置されます。
サッカーボールを移動させる
キーボード操作を可能にするには、次のようにmixinを追加します。
SampleGameクラスにHasKeyboardHandlerComponentsを追加
import 'package:flame/events.dart';
class SampleGame extends FlameGame with HasKeyboardHandlerComponents {
・・・
}
BallクラスにKeyboardHandlerを追加
class Ball extends SpriteComponent with HasGameRef<SampleGame>, KeyboardHandler{
・・・
}
これによりボールに対してキーボードの操作を検知できるようになります。
Ballクラスにボールを移動させる処理を書いていきましょう。
import 'package:flutter/services.dart'; // 追加
class Ball extends SpriteComponent with HasGameRef<SampleGame>, KeyboardHandler{
// 追加
int horizontalDirection = 0; // 水平方向の向き:左か右か
final Vector2 velocity = Vector2.zero();
final double moveSpeed = 200;
@override
Future<void> onLoad() async {
// 画像の読み込み
final ball = await Flame.images.load("ball.png");
// ボールのサイズ
size = Vector2(100, 100);
// 画面のサイズを取得
final screenHeight = gameRef.size.y;
// ボールの配置位置を左下に配置(Y座標:画面の高さ - ボールのサイズの高さ - 20)
position = Vector2(50, screenHeight - size.y - 20);
sprite = Sprite(ball);
}
// キーボードの操作イベント
@override
bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
// 水平方向の向きをリセット
horizontalDirection = 0;
// Aか左を押したら、左方向(-1)をセット
horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyA) ||
keysPressed.contains(LogicalKeyboardKey.arrowLeft))
? -1
: 0;
// Dか→を押したら、右方向(1)をセット
horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyD) ||
keysPressed.contains(LogicalKeyboardKey.arrowRight))
? 1
: 0;
return true;
}
@override
void update(double dt) {
// ボールの速度を更新
velocity.x = horizontalDirection * moveSpeed;
// ボールの位置を更新
position += velocity * dt;
super.update(dt);
}
}
onKeyEvent
でキーボードを操作したときの処理を記述します。
水平方向の左右の向きを表す変数horizontalDirection
を用紙し、左(またはA)を押した場合-1を、右(またはD)を押した場合1をセットし、進行方向を決定します。
update
では進行方向にボールを移動させています。
この状態、実行すると以下のようになります。
移動中にサッカーボールを回転させる
キーボードでボールの移動ができるようになりましたが、少し不自然なのでボールの回転も追加しておきましょう。
import 'dart:math'; // 追加
class Ball extends SpriteComponent with HasGameRef<SampleGame>, KeyboardHandler{
int horizontalDirection = 0; // 水平方向の向き:左か右か
final Vector2 velocity = Vector2.zero();
final double moveSpeed = 200;
// 追加
double rotationSpeed = 5.0; // 回転スピード
double rotationAngle = 0.0; // 回転角度
@override
Future<void> onLoad() async {
// 画像の読み込み
final ball = await Flame.images.load("ball.png");
// ボールのサイズ
size = Vector2(100, 100);
// 画面のサイズを取得
final screenHeight = gameRef.size.y;
// ボールの配置位置を左下に配置(Y座標:画面の高さ - ボールのサイズの高さ - 20)
position = Vector2(50, screenHeight - size.y - 20);
// 追加:ボールの中心をアンカーとする(anchor:コンポーネントの位置や操作の基準点)
anchor = Anchor.center;
sprite = Sprite(ball);
}
// キーボードの操作イベント
@override
bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
// 水平方向の向きをリセット
horizontalDirection = 0;
// Aか左を押したら、左方向(-1)をセット
horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyA) ||
keysPressed.contains(LogicalKeyboardKey.arrowLeft))
? -1
: 0;
// Dか→を押したら、右方向(1)をセット
horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyD) ||
keysPressed.contains(LogicalKeyboardKey.arrowRight))
? 1
: 0;
return true;
}
@override
void update(double dt) {
// ボールの速度を更新
velocity.x = horizontalDirection * moveSpeed;
// ボールの位置を更新
position += velocity * dt;
// 追加:ボールが左右に移動するときに回転させる
if (horizontalDirection != 0) {
rotationAngle += rotationSpeed * horizontalDirection * dt;
// 回転角度が2π(360度)を超えた場合、 0度に戻す
if (rotationAngle > 2 * pi) {
rotationAngle -= 2 * pi;
} else if (rotationAngle < -2 * pi) {
// 回転角度が-2π(-360度)を超えた場合,0度に戻す
rotationAngle += 2 * pi;
}
// ボールの角度をセット
angle = rotationAngle;
}
super.update(dt);
}
}
update
で右に移動中は右回転に、左に移動中は左回転にしています。
anchor = Anchor.center
でボールの中心をアンカーにしておかないと、変な動きになるので注意してください。
実行すると以下のようになります。
全体のコード
import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/flame.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
final game = SampleGame();
runApp(
GameWidget(game: game)
);
}
class SampleGame extends FlameGame with HasKeyboardHandlerComponents {
@override
Future<void> onLoad() async {
add(Ball());
}
}
class Ball extends SpriteComponent with HasGameRef<SampleGame>, KeyboardHandler{
int horizontalDirection = 0; // 水平方向の向き:左か右か
final Vector2 velocity = Vector2.zero();
final double moveSpeed = 200;
double rotationSpeed = 5.0; // 回転スピード
double rotationAngle = 0.0; // 回転角度
@override
Future<void> onLoad() async {
// 画像の読み込み
final ball = await Flame.images.load("ball.png");
// ボールのサイズ
size = Vector2(100, 100);
// 画面のサイズを取得
final screenHeight = gameRef.size.y;
// ボールの配置位置を左下に配置(Y座標:画面の高さ - ボールのサイズの高さ - 20)
position = Vector2(50, screenHeight - size.y - 20);
// ボールの中心をアンカーとする(anchor:コンポーネントの位置や操作の基準点)
anchor = Anchor.center;
sprite = Sprite(ball);
}
// キーボードの操作イベント
@override
bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
// 水平方向の向きをリセット
horizontalDirection = 0;
// Aか左を押したら、左方向(-1)をセット
horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyA) ||
keysPressed.contains(LogicalKeyboardKey.arrowLeft))
? -1
: 0;
// Dか→を押したら、右方向(1)をセット
horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyD) ||
keysPressed.contains(LogicalKeyboardKey.arrowRight))
? 1
: 0;
return true;
}
@override
void update(double dt) {
// ボールの速度を更新
velocity.x = horizontalDirection * moveSpeed;
// ボールの位置を更新
position += velocity * dt;
// ボールが左右に移動するときに回転させる
if (horizontalDirection != 0) {
rotationAngle += rotationSpeed * horizontalDirection * dt;
// 回転角度が2π(360度)を超えた場合、 0度に戻す
if (rotationAngle > 2 * pi) {
rotationAngle -= 2 * pi;
} else if (rotationAngle < -2 * pi) {
// 回転角度が-2π(-360度)を超えた場合,0度に戻す
rotationAngle += 2 * pi;
}
// ボールの角度をセット
angle = rotationAngle;
}
super.update(dt);
}
}
Comment