blob: c61545128949057532b64d8b48e94a773f4126cb [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:sky/mojo/asset_bundle.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/rendering/object.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/button_base.dart';
import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/framework.dart';
import 'package:sky/widgets/title.dart';
import 'package:sky/widgets/theme.dart';
import 'game_demo.dart';
import 'sprites.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;
GameDemoApp _app;
Map<String,SoundEffect> _sounds = {};
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([
'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);
_app = new GameDemoApp();
assert(_spriteSheet.image != null);
SoundTrackPlayer stPlayer = SoundTrackPlayer.sharedInstance();
SoundTrack music = await stPlayer.load(_bundle.load('assets/temp_music.aac'));
stPlayer.play(music);
runApp(_app);
}
class GameDemoApp extends App {
NavigationState _navigationState;
NodeWithSize _game;
int _lastScore = 0;
void initState() {
_navigationState = new NavigationState([
new Route(
name: '/',
builder: _buildMainScene
),
new Route(
name: '/game',
builder: _buildGameScene
),
]);
super.initState();
}
Widget build() {
// TODO(viktork): The task bar purple is the wrong purple, we may need
// a custom theme swatch to match the purples in the sprites.
ThemeData theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: colors.Purple
);
return new Theme(
data: theme,
child: new Title(
title: 'Asteroids',
child: new Navigator(_navigationState)
)
);
}
Widget _buildGameScene(navigator, route) {
return new SpriteWidget(_game, SpriteBoxTransformMode.fixedWidth);
}
Widget _buildMainScene(navigator, route) {
return new Stack([
new SpriteWidget(new MainScreenBackground(), SpriteBoxTransformMode.fixedWidth),
new Flex([
new TextureButton(
onPressed: () {
_game = new GameDemoNode(
_imageMap,
_spriteSheet,
_spriteSheetUI,
_sounds,
(lastScore) {
setState(() {_lastScore = lastScore;});
navigator.pop();
}
);
navigator.pushNamed('/game');
},
texture: _spriteSheetUI['btn_play_up.png'],
textureDown: _spriteSheetUI['btn_play_down.png'],
width: 128.0,
height: 128.0
),
new Text(
"Last Score: $_lastScore",
style: new TextStyle(fontSize:20.0)
)
],
direction: FlexDirection.vertical,
justifyContent: FlexJustifyContent.center)
]);
}
}
class TextureButton extends ButtonBase {
TextureButton({
Key key,
this.onPressed,
this.texture,
this.textureDown,
this.width: 128.0,
this.height: 128.0
}) : super(key: key);
final Function onPressed;
final Texture texture;
final Texture textureDown;
final double width;
final double height;
Widget buildContent() {
return new Listener(
child: new Container(
width: width,
height: height,
child: new CustomPaint(
callback: paintCallback,
token: new _TextureButtonToken(
highlight,
texture,
textureDown,
width,
height
)
)
),
onPointerUp: (_) {
if (onPressed != null) onPressed();
}
);
}
void paintCallback(PaintingCanvas canvas, Size size) {
if (texture == null)
return;
canvas.save();
if (highlight && textureDown != null) {
// Draw down state
canvas.scale(size.width / textureDown.size.width, size.height / textureDown.size.height);
textureDown.drawTexture(canvas, Point.origin, new Paint());
} else {
// Draw up state
canvas.scale(size.width / texture.size.width, size.height / texture.size.height);
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);
}
}