blob: c3ac27697b7445acacfa52189334678694923129 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
import 'game_demo.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(new Uri.directory(Uri.base.origin));
}
final AssetBundle _bundle = _initBundle();
ImageMap _imageMap;
SpriteSheet _spriteSheet;
SpriteSheet _spriteSheetUI;
Map<String, SoundEffect> _sounds = <String, SoundEffect>{};
main() async {
_imageMap = new ImageMap(_bundle);
// Use a list to wait on all loads in parallel just before starting the app.
List loads = [];
loads.add(_imageMap.load(<String>[
'assets/nebula.png',
'assets/sprites.png',
'assets/starfield.png',
'assets/game_ui.png',
]));
// TODO(eseidel): SoundEffect doesn't really do anything except hold a future.
_sounds['explosion'] = new SoundEffect(_bundle.load('assets/explosion.wav'));
_sounds['laser'] = new SoundEffect(_bundle.load('assets/laser.wav'));
loads.addAll([
_sounds['explosion'].load(),
_sounds['laser'].load(),
]);
await Future.wait(loads);
// TODO(eseidel): These load in serial which is bad for startup!
String json = await _bundle.loadString('assets/sprites.json');
_spriteSheet = new SpriteSheet(_imageMap['assets/sprites.png'], json);
json = await _bundle.loadString('assets/game_ui.json');
_spriteSheetUI = new SpriteSheet(_imageMap['assets/game_ui.png'], json);
assert(_spriteSheet.image != null);
SoundTrackPlayer stPlayer = SoundTrackPlayer.sharedInstance();
SoundTrack music = await stPlayer.load(_bundle.load('assets/temp_music.aac'));
stPlayer.play(music);
runApp(new GameDemo());
}
// TODO(viktork): The task bar purple is the wrong purple, we may need
// a custom theme swatch to match the purples in the sprites.
final ThemeData _theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.purple
);
class GameDemo extends StatefulComponent {
GameDemoState createState() => new GameDemoState();
}
class GameDemoState extends State<GameDemo> {
NodeWithSize _game;
int _lastScore = 0;
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Asteroids',
theme: _theme,
routes: <String, RouteBuilder>{
'/': _buildMainScene,
'/game': _buildGameScene
}
);
}
Widget _buildGameScene(RouteArguments args) {
return new SpriteWidget(_game, SpriteBoxTransformMode.fixedWidth);
}
Widget _buildMainScene(RouteArguments args) {
NavigatorState navigatorState = Navigator.of(args.context);
return new Stack(<Widget>[
new SpriteWidget(new MainScreenBackground(), SpriteBoxTransformMode.fixedWidth),
new Column(<Widget>[
new TextureButton(
onPressed: () {
_game = new GameDemoNode(
_imageMap,
_spriteSheet,
_spriteSheetUI,
_sounds,
(int lastScore) {
setState(() { _lastScore = lastScore; });
navigatorState.pop();
}
);
navigatorState.pushNamed('/game');
},
texture: _spriteSheetUI['btn_play_up.png'],
textureDown: _spriteSheetUI['btn_play_down.png'],
width: 128.0,
height: 128.0
),
new DefaultTextStyle(
child: new Text(
"Last Score: $_lastScore"
),
style: new TextStyle(fontSize:20.0)
)
],
justifyContent: FlexJustifyContent.center
)
]);
}
}
class TextureButton extends StatefulComponent {
TextureButton({
Key key,
this.onPressed,
this.texture,
this.textureDown,
this.width: 128.0,
this.height: 128.0
}) : super(key: key);
final VoidCallback onPressed;
final Texture texture;
final Texture textureDown;
final double width;
final double height;
TextureButtonState createState() => new TextureButtonState();
}
class TextureButtonState extends State<TextureButton> {
bool _highlight = false;
Widget build(BuildContext context) {
return new GestureDetector(
child: new Container(
width: config.width,
height: config.height,
child: new CustomPaint(
onPaint: paintCallback,
token: new _TextureButtonToken(
_highlight,
config.texture,
config.textureDown,
config.width,
config.height
)
)
),
onTapDown: (_) {
setState(() {
_highlight = true;
});
},
onTap: () {
setState(() {
_highlight = false;
});
if (config.onPressed != null)
config.onPressed();
},
onTapCancel: () {
setState(() {
_highlight = false;
});
}
);
}
void paintCallback(PaintingCanvas canvas, Size size) {
if (config.texture == null)
return;
canvas.save();
if (_highlight && config.textureDown != null) {
// Draw down state
canvas.scale(size.width / config.textureDown.size.width, size.height / config.textureDown.size.height);
config.textureDown.drawTexture(canvas, Point.origin, new Paint());
} else {
// Draw up state
canvas.scale(size.width / config.texture.size.width, size.height / config.texture.size.height);
config.texture.drawTexture(canvas, Point.origin, new Paint());
}
canvas.restore();
}
}
class _TextureButtonToken {
_TextureButtonToken(
this._highlight,
this._texture,
this._textureDown,
this._width,
this._height
);
final bool _highlight;
final Texture _texture;
final Texture _textureDown;
final double _width;
final double _height;
bool operator== (other) {
return
other is _TextureButtonToken &&
_highlight == other._highlight &&
_texture == other._texture &&
_textureDown == other._textureDown &&
_width == other._width &&
_height == other._height;
}
int get hashCode {
int value = 373;
value = 37 * value * _highlight.hashCode;
value = 37 * value * _texture.hashCode;
value = 37 * value * _textureDown.hashCode;
value = 37 * value * _width.hashCode;
value = 37 * value * _height.hashCode;
return value;
}
}
class MainScreenBackground extends NodeWithSize {
MainScreenBackground() : super(new Size(320.0, 320.0)) {
assert(_spriteSheet.image != null);
StarField starField = new StarField(_spriteSheet, 200, true);
addChild(starField);
}
void paint(PaintingCanvas canvas) {
canvas.drawRect(new Rect.fromLTWH(0.0, 0.0, 320.0, 320.0), new Paint()..color=new Color(0xff000000));
super.paint(canvas);
}
}