Commit ab3ae1e1 authored by Viktor Lidholt's avatar Viktor Lidholt

Removes demo game from repository (it's now in its own)

parent 04dfa0bf
# 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("//sky/build/sky_app.gni")
sky_app("game") {
main_dart = "lib/main.dart"
manifest = "flutter.yaml"
if (is_android) {
apk_name = "Asteroids"
deps = [
"//examples/game/apk:resources",
]
} else if (is_ios) {
info_plist = "ios/Info.plist"
launcher_resources = [
"assets/Icon.png",
"assets/Icon@2x.png",
"ios/LaunchScreen.storyboardc",
]
} else if (is_mac) {
info_plist = "mac/Info.plist"
xibs = [ "mac/sky_mac.xib" ]
}
}
Assets for this game are from Galactic Guardian:
https://github.com/slembcke/GalacticGuardian.spritebuilder
And are used under MIT license:
https://github.com/slembcke/GalacticGuardian.spritebuilder/pull/2
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.domokit.asteroids">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<application android:icon="@mipmap/ic_launcher" android:name="org.domokit.sky.shell.SkyApplication" android:label="Asteroids">
<activity android:name="org.domokit.sky.shell.SkyActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
# 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.
assert(is_android)
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_resources("resources") {
resource_dirs = [ "res" ]
android_manifest = "AndroidManifest.xml"
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
{"frames": [
{
"filename": "bar_shield.png",
"frame": {"x":2,"y":954,"w":412,"h":100},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":412,"h":100},
"sourceSize": {"w":412,"h":100},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "bar_shield_fill.png",
"frame": {"x":2,"y":1156,"w":320,"h":72},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":320,"h":72},
"sourceSize": {"w":320,"h":72},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "btn_play_down.png",
"frame": {"x":2,"y":484,"w":468,"h":468},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":16,"w":468,"h":468},
"sourceSize": {"w":472,"h":484},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "btn_play_up.png",
"frame": {"x":2,"y":2,"w":468,"h":480},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":4,"w":468,"h":480},
"sourceSize": {"w":472,"h":484},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "coinboard.png",
"frame": {"x":366,"y":1056,"w":261,"h":100},
"rotated": true,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":261,"h":100},
"sourceSize": {"w":261,"h":100},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_0.png",
"frame": {"x":416,"y":954,"w":38,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":22,"w":38,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_1.png",
"frame": {"x":299,"y":1286,"w":16,"h":57},
"rotated": true,
"trimmed": true,
"spriteSourceSize": {"x":45,"y":25,"w":16,"h":57},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_2.png",
"frame": {"x":324,"y":1156,"w":38,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":22,"w":38,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_3.png",
"frame": {"x":197,"y":1230,"w":35,"h":63},
"rotated": true,
"trimmed": true,
"spriteSourceSize": {"x":26,"y":22,"w":35,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_4.png",
"frame": {"x":197,"y":1267,"w":38,"h":57},
"rotated": true,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":25,"w":38,"h":57},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_5.png",
"frame": {"x":324,"y":1221,"w":38,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":22,"w":38,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_6.png",
"frame": {"x":2,"y":1230,"w":38,"h":63},
"rotated": true,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":22,"w":38,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_7.png",
"frame": {"x":262,"y":1230,"w":35,"h":60},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":26,"y":22,"w":35,"h":60},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_8.png",
"frame": {"x":67,"y":1230,"w":38,"h":63},
"rotated": true,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":22,"w":38,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "number_9.png",
"frame": {"x":132,"y":1230,"w":38,"h":63},
"rotated": true,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":22,"w":38,"h":63},
"sourceSize": {"w":84,"h":107},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "scoreboard.png",
"frame": {"x":2,"y":1056,"w":362,"h":98},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":362,"h":98},
"sourceSize": {"w":362,"h":98},
"pivot": {"x":0.5,"y":0.5}
}],
"meta": {
"app": "http://www.codeandweb.com/texturepacker",
"version": "1.0",
"image": "game_ui.png",
"format": "RGBA8888",
"size": {"w":472,"h":1319},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:2fc7dfe766eba152274e2661737d6b51:b44b32d1e0a4146b3591d51b12f2d7ae:10ac111e32c27e51f4e8444dbb39eff6$"
}
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
{"frames": [
{
"filename": "asteroid_big_0.nrm.png",
"frame": {"x":2,"y":260,"w":200,"h":188},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":200,"h":188},
"sourceSize": {"w":200,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_0.png",
"frame": {"x":2,"y":450,"w":200,"h":167},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":21,"w":200,"h":167},
"sourceSize": {"w":200,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_1.nrm.png",
"frame": {"x":2,"y":619,"w":204,"h":166},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":204,"h":166},
"sourceSize": {"w":204,"h":166},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_1.png",
"frame": {"x":2,"y":787,"w":204,"h":166},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":204,"h":166},
"sourceSize": {"w":204,"h":166},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_2.nrm.png",
"frame": {"x":204,"y":335,"w":194,"h":165},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":194,"h":165},
"sourceSize": {"w":194,"h":165},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_2.png",
"frame": {"x":208,"y":502,"w":194,"h":165},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":194,"h":165},
"sourceSize": {"w":194,"h":167},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_0.nrm.png",
"frame": {"x":347,"y":843,"w":102,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":102,"h":84},
"sourceSize": {"w":102,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_0.png",
"frame": {"x":347,"y":929,"w":102,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":102,"h":84},
"sourceSize": {"w":102,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_1.nrm.png",
"frame": {"x":404,"y":463,"w":96,"h":102},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":102},
"sourceSize": {"w":96,"h":102},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_1.png",
"frame": {"x":404,"y":567,"w":96,"h":102},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":102},
"sourceSize": {"w":96,"h":106},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_2.nrm.png",
"frame": {"x":347,"y":671,"w":109,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":109,"h":84},
"sourceSize": {"w":109,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_2.png",
"frame": {"x":347,"y":757,"w":109,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":109,"h":84},
"sourceSize": {"w":109,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "coin.png",
"frame": {"x":429,"y":270,"w":42,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":4,"w":42,"h":47},
"sourceSize": {"w":54,"h":56},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "enemy_destroyer_1.png",
"frame": {"x":260,"y":193,"w":167,"h":140},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":10,"y":31,"w":167,"h":140},
"sourceSize": {"w":188,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "enemy_scout_0.png",
"frame": {"x":400,"y":335,"w":107,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":1,"w":107,"h":126},
"sourceSize": {"w":129,"h":129},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "explosion_flare.png",
"frame": {"x":451,"y":2,"w":56,"h":209},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":56,"h":209},
"sourceSize": {"w":64,"h":256},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "explosion_particle.png",
"frame": {"x":204,"y":260,"w":36,"h":60},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":1,"w":36,"h":60},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "explosion_ring.png",
"frame": {"x":2,"y":2,"w":256,"h":256},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":256,"h":256},
"sourceSize": {"w":256,"h":256},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "fire_particle.png",
"frame": {"x":429,"y":213,"w":55,"h":55},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":55,"h":55},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "laser.png",
"frame": {"x":458,"y":671,"w":37,"h":76},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":76},
"sourceSize": {"w":37,"h":76},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "shield.png",
"frame": {"x":260,"y":2,"w":189,"h":189},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":189,"h":189},
"sourceSize": {"w":189,"h":189},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "ship.nrm.png",
"frame": {"x":208,"y":669,"w":137,"h":167},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":137,"h":167},
"sourceSize": {"w":137,"h":167},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "ship.png",
"frame": {"x":208,"y":838,"w":137,"h":167},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":25,"y":10,"w":137,"h":167},
"sourceSize": {"w":188,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star_0.png",
"frame": {"x":2,"y":955,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":62,"h":62},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star_1.png",
"frame": {"x":66,"y":955,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":62,"h":62},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star_2.png",
"frame": {"x":130,"y":955,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":62,"h":62},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
}],
"meta": {
"app": "http://www.codeandweb.com/texturepacker",
"version": "1.0",
"image": "sprites.png",
"format": "RGBA8888",
"size": {"w":509,"h":1019},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:2164a72d7de59aa3603277aa505ff73b:f339feca6ccc1f78132ecc733c94dbc5:1eabdf11f75e3a4fe3147baf7b5be24b$"
}
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _bundle = _initBundle();
ImageMap _images;
SpriteSheet _spriteSheet;
main() async {
_images = new ImageMap(_bundle);
await _images.load(<String>[
'assets/checker.png',
'assets/line_effects.png'
]);
assert(_images["assets/checker.png"] != null);
runApp(new TestApp());
}
class TestApp extends StatefulComponent {
TestAppState createState() => new TestAppState();
}
final ThemeData _theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.blue
);
class TestAppState extends State<TestApp> {
TestAppState() {
_testBed = new TestBed(_labelTexts[_selectedLine]);
}
TestBed _testBed;
int _selectedLine = 0;
List<String> _labelTexts = <String>[
"Colored",
"Smoke",
"Electric",
"Rocket Trail"
];
Widget build(BuildContext context) {
return new MaterialApp(
title: 'EffectLine Demo',
theme: _theme,
routes: <String, RouteBuilder>{
'/': _buildColumn
}
);
}
Column _buildColumn(RouteArguments args) {
return new Column(<Widget>[
new Flexible(child: _buildSpriteWidget()),
_buildTabBar()
]);
}
TabBar _buildTabBar() {
return new TabBar(
labels: _buildTabLabels(),
selectedIndex: _selectedLine,
onChanged: (int selectedLine) {
setState(() {
_selectedLine = selectedLine;
});
}
);
}
List<TabLabel> _buildTabLabels() {
List<TabLabel> labels = <TabLabel>[];
for (String text in _labelTexts)
labels.add(new TabLabel(text: text));
return labels;
}
SpriteWidget _buildSpriteWidget() {
_testBed.setupLine(_labelTexts[_selectedLine]);
return new SpriteWidget(
_testBed,
SpriteBoxTransformMode.letterbox
);
}
}
class TestBed extends NodeWithSize {
EffectLine _line;
TestBed(String lineType) : super(new Size(1024.0, 1024.0)) {
userInteractionEnabled = true;
setupLine(lineType);
}
void setupLine(String lineType) {
if (_line != null) {
_line.removeFromParent();
}
if (lineType == "Colored") {
// Create a line with no texture and a color sequence
_line = new EffectLine(
texture: null,
colorSequence: new ColorSequence.fromStartAndEndColor(new Color(0xaaffff00), new Color(0xaaff9900)),
widthMode: EffectLineWidthMode.barrel,
minWidth: 10.0,
maxWidth: 15.0,
fadeAfterDelay: 1.0,
fadeDuration: 1.0
);
} else if (lineType == "Smoke") {
Texture baseTexture = new Texture(_images['assets/line_effects.png']);
Texture smokyLineTexture = baseTexture.textureFromRect(new Rect.fromLTRB(0.0, 0.0, 1024.0, 128.0));
_line = new EffectLine(
texture: smokyLineTexture,
textureLoopLength: 300.0,
colorSequence: new ColorSequence.fromStartAndEndColor(new Color(0xffffffff), new Color(0x00ffffff)),
widthMode: EffectLineWidthMode.barrel,
minWidth: 20.0,
maxWidth: 80.0,
animationMode: EffectLineAnimationMode.scroll
);
} else if (lineType == "Electric") {
Texture baseTexture = new Texture(_images['assets/line_effects.png']);
Texture electricLineTexture = baseTexture.textureFromRect(new Rect.fromLTRB(0.0, 384.0, 1024.0, 512.0));
_line = new EffectLine(
texture: electricLineTexture,
textureLoopLength: 300.0,
widthMode: EffectLineWidthMode.barrel,
minWidth: 20.0,
maxWidth: 100.0,
animationMode: EffectLineAnimationMode.random
);
} else if (lineType == "Rocket Trail") {
Texture baseTexture = new Texture(_images['assets/line_effects.png']);
Texture trailLineTexture = baseTexture.textureFromRect(new Rect.fromLTRB(0.0, 896.0, 1024.0, 1024.0));
_line = new EffectLine(
texture: trailLineTexture,
textureLoopLength: 300.0,
widthMode: EffectLineWidthMode.barrel,
minWidth: 20.0,
maxWidth: 40.0,
widthGrowthSpeed: 40.0,
fadeAfterDelay: 0.5,
fadeDuration: 1.5
);
}
addChild(_line);
}
bool handleEvent(SpriteBoxEvent event) {
if (event.type == "pointerdown")
_line.points = <Point>[];
if (event.type == "pointerdown" || event.type == "pointermove") {
Point pos = convertPointToNodeSpace(event.boxPosition);
_line.addPoint(pos);
}
return true;
}
}
assets:
- assets/nebula.png
- assets/sprites.json
- assets/sprites.png
- assets/starfield.png
- assets/game_ui.png
- assets/game_ui.json
- assets/explosion.wav
- assets/laser.wav
- assets/levelup.wav
- assets/pickup.wav
- assets/temp_music.aac
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<!--
This executable name must match the name of the app provided to the
ios_app GN template
-->
<key>CFBundleExecutable</key>
<string>game_app</string>
<key>CFBundleDisplayName</key>
<string>Asteroids</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>CFBundleIdentifier</key>
<string>com.google.sky.game</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>game_app</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>DTPlatformName</key>
<string>iphonesimulator</string>
<key>DTSDKName</key>
<string>iphonesimulator8.3</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>8.3</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneSimulator</string>
</array>
</dict>
</plist>
part of game;
typedef void PointSetterCallback(Point value);
class ActionCircularMove extends ActionInterval {
ActionCircularMove(this.setter, this.center, this.radius, this.startAngle, this.clockWise, double duration) : super (duration);
final PointSetterCallback setter;
final Point center;
final double radius;
final double startAngle;
final bool clockWise;
void update(double t) {
if (!clockWise) t = -t;
double rad = radians(startAngle + t * 360.0);
Offset offset = new Offset(math.cos(rad) * radius, math.sin(rad) * radius);
Point pos = center + offset;
setter(pos);
}
}
class ActionOscillate extends ActionInterval {
ActionOscillate(this.setter, this.center, this.radius, double duration) : super(duration);
final PointSetterCallback setter;
final Point center;
final double radius;
void update(double t) {
double rad = radians(t * 360.0);
Offset offset = new Offset(math.sin(rad) * radius, 0.0);
setter(center + offset);
}
}
part of game;
class Explosion extends Node {
Explosion() {
zPosition = 10.0;
}
}
class ExplosionBig extends Explosion {
ExplosionBig(SpriteSheet sheet) {
// Add particles
ParticleSystem particlesDebris = new ParticleSystem(
sheet["explosion_particle.png"],
rotateToMovement: true,
startRotation:90.0,
startRotationVar: 0.0,
endRotation: 90.0,
startSize: 0.3,
startSizeVar: 0.1,
endSize: 0.3,
endSizeVar: 0.1,
numParticlesToEmit: 25,
emissionRate:1000.0,
greenVar: 127,
redVar: 127,
life: 0.75,
lifeVar: 0.5
);
particlesDebris.zPosition = 1010.0;
addChild(particlesDebris);
ParticleSystem particlesFire = new ParticleSystem(
sheet["fire_particle.png"],
colorSequence: new ColorSequence(<Color>[new Color(0xffffff33), new Color(0xffff3333), new Color(0x00ff3333)], <double>[0.0, 0.5, 1.0]),
numParticlesToEmit: 25,
emissionRate: 1000.0,
startSize: 0.5,
startSizeVar: 0.1,
endSize: 0.5,
endSizeVar: 0.1,
posVar: new Point(10.0, 10.0),
speed: 10.0,
speedVar: 5.0,
life: 0.75,
lifeVar: 0.5
);
particlesFire.zPosition = 1011.0;
addChild(particlesFire);
// Add ring
Sprite spriteRing = new Sprite(sheet["explosion_ring.png"]);
spriteRing.transferMode = ui.TransferMode.plus;
addChild(spriteRing);
Action scale = new ActionTween((double a) { spriteRing.scale = a; }, 0.2, 1.0, 0.75);
Action scaleAndRemove = new ActionSequence(<Action>[scale, new ActionRemoveNode(spriteRing)]);
Action fade = new ActionTween((double a) { spriteRing.opacity = a; }, 1.0, 0.0, 0.75);
actions.run(scaleAndRemove);
actions.run(fade);
// Add streaks
for (int i = 0; i < 5; i++) {
Sprite spriteFlare = new Sprite(sheet["explosion_flare.png"]);
spriteFlare.pivot = new Point(0.3, 1.0);
spriteFlare.scaleX = 0.3;
spriteFlare.transferMode = ui.TransferMode.plus;
spriteFlare.rotation = randomDouble() * 360.0;
addChild(spriteFlare);
double multiplier = randomDouble() * 0.3 + 1.0;
Action scale = new ActionTween((double a) { spriteFlare.scaleY = a; }, 0.3 * multiplier, 0.8, 0.75 * multiplier);
Action scaleAndRemove = new ActionSequence(<Action>[scale, new ActionRemoveNode(spriteFlare)]);
Action fadeIn = new ActionTween((double a) { spriteFlare.opacity = a; }, 0.0, 1.0, 0.25 * multiplier);
Action fadeOut = new ActionTween((double a) { spriteFlare.opacity = a; }, 1.0, 0.0, 0.5 * multiplier);
Action fadeInOut = new ActionSequence(<Action>[fadeIn, fadeOut]);
actions.run(scaleAndRemove);
actions.run(fadeInOut);
}
}
}
class ExplosionMini extends Explosion {
ExplosionMini(SpriteSheet sheet) {
for (int i = 0; i < 2; i++) {
Sprite star = new Sprite(sheet["star_0.png"]);
star.scale = 0.5;
star.colorOverlay = new Color(0xff95f4fb);
star.transferMode = ui.TransferMode.plus;
addChild(star);
double rotationStart = randomDouble() * 90.0;
double rotationEnd = 180.0 + randomDouble() * 90.0;
if (i == 0) {
rotationStart = -rotationStart;
rotationEnd = -rotationEnd;
}
ActionTween rotate = new ActionTween((double a) { star.rotation = a; }, rotationStart, rotationEnd, 0.2);
actions.run(rotate);
ActionTween fade = new ActionTween((double a) { star.opacity = a; }, 1.0, 0.0, 0.2);
actions.run(fade);
}
ActionSequence seq = new ActionSequence(<Action>[new ActionDelay(0.2), new ActionRemoveNode(this)]);
actions.run(seq);
}
}
part of game;
class Flash extends NodeWithSize {
Flash(Size size, this.duration) : super(size) {
ActionTween fade = new ActionTween((double a) { _opacity = a; }, 1.0, 0.0, duration);
ActionSequence seq = new ActionSequence(<Action>[fade, new ActionRemoveNode(this)]);
actions.run(seq);
}
double duration;
double _opacity = 1.0;
Paint _cachedPaint = new Paint();
void paint(PaintingCanvas canvas) {
// Update the color
_cachedPaint.color = new Color.fromARGB((255.0 * _opacity).toInt(),
255, 255, 255);
// Fill the area
applyTransformForPivot(canvas);
canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, size.width, size.height),
_cachedPaint);
}
}
library game;
import 'dart:async';
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
import 'package:vector_math/vector_math_64.dart';
part 'custom_actions.dart';
part 'explosions.dart';
part 'flash.dart';
part 'game_demo_node.dart';
part 'game_objects.dart';
part 'game_object_factory.dart';
part 'player_state.dart';
part 'power_bar.dart';
part 'repeated_image.dart';
part 'star_field.dart';
part of game;
final double _gameSizeWidth = 320.0;
double _gameSizeHeight = 320.0;
final double _chunkSpacing = 640.0;
final int _chunksPerLevel = 9;
final bool _drawDebug = false;
typedef void GameOverCallback(int score);
class GameDemoNode extends NodeWithSize {
GameDemoNode(
this._images,
this._spritesGame,
this._spritesUI,
this._sounds,
this._gameOverCallback
): super(new Size(320.0, 320.0)) {
// Add background
_background = new RepeatedImage(_images["assets/starfield.png"]);
addChild(_background);
// Create starfield
_starField = new StarField(_spritesGame, 200);
addChild(_starField);
// Add nebula
_nebula = new RepeatedImage(_images["assets/nebula.png"], ui.TransferMode.plus);
addChild(_nebula);
// Setup game screen, it will always be anchored to the bottom of the screen
_gameScreen = new Node();
addChild(_gameScreen);
// Setup the level and add it to the screen, the level is the node where
// all our game objects live. It is moved to scroll the game
_level = new Level();
_gameScreen.addChild(_level);
// Add heads up display
_playerState = new PlayerState(_spritesUI, _spritesGame);
addChild(_playerState);
_objectFactory = new GameObjectFactory(_spritesGame, _sounds, _level, _playerState);
_level.ship = new Ship(_objectFactory);
_level.ship.setupActions();
_level.addChild(_level.ship);
// Add the joystick
_joystick = new VirtualJoystick();
_gameScreen.addChild(_joystick);
// Add initial game objects
addObjects();
}
// Resources
ImageMap _images;
Map<String, SoundEffect> _sounds;
SpriteSheet _spritesGame;
SpriteSheet _spritesUI;
// Sounds
SoundEffectPlayer _effectPlayer = SoundEffectPlayer.sharedInstance();
// Callback
GameOverCallback _gameOverCallback;
// Game screen nodes
Node _gameScreen;
VirtualJoystick _joystick;
GameObjectFactory _objectFactory;
Level _level;
StarField _starField;
RepeatedImage _background;
RepeatedImage _nebula;
PlayerState _playerState;
// Game properties
double _scroll = 0.0;
int _framesToFire = 0;
int _framesBetweenShots = 20;
bool _gameOver = false;
void spriteBoxPerformedLayout() {
_gameSizeHeight = spriteBox.visibleArea.height;
_gameScreen.position = new Point(0.0, _gameSizeHeight);
}
void update(double dt) {
// Scroll the level
_scroll = _level.scroll(_playerState.scrollSpeed);
_starField.move(0.0, _playerState.scrollSpeed);
_background.move(_playerState.scrollSpeed * 0.1);
_nebula.move(_playerState.scrollSpeed);
// Add objects
addObjects();
// Move the ship
if (!_gameOver) {
_level.ship.applyThrust(_joystick.value, _scroll);
}
// Add shots
if (_framesToFire == 0 && _joystick.isDown && !_gameOver) {
fire();
_framesToFire = (_playerState.speedLaserActive) ? _framesBetweenShots ~/ 2 : _framesBetweenShots;
}
if (_framesToFire > 0) _framesToFire--;
// Move game objects
for (Node node in _level.children) {
if (node is GameObject) {
node.move();
}
}
// Remove offscreen game objects
for (int i = _level.children.length - 1; i >= 0; i--) {
Node node = _level.children[i];
if (node is GameObject) {
node.removeIfOffscreen(_scroll);
}
}
if (_gameOver) return;
// Check for collisions between lasers and objects that can take damage
List<Laser> lasers = <Laser>[];
for (Node node in _level.children) {
if (node is Laser) lasers.add(node);
}
List<GameObject> damageables = <GameObject>[];
for (Node node in _level.children) {
if (node is GameObject && node.canBeDamaged) damageables.add(node);
}
for (Laser laser in lasers) {
for (GameObject damageable in damageables) {
if (laser.collidingWith(damageable)) {
// Hit something that can take damage
damageable.addDamage(laser.impact);
laser.destroy();
}
}
}
// Check for collsions between ship and objects that can damage the ship
List<Node> nodes = new List<Node>.from(_level.children);
for (Node node in nodes) {
if (node is GameObject && node.canDamageShip) {
if (node.collidingWith(_level.ship)) {
if (_playerState.shieldActive) {
// Hit, but saved by the shield!
node.destroy();
} else {
// The ship was hit :(
killShip();
}
}
} else if (node is GameObject && node.canBeCollected) {
if (node.collidingWith(_level.ship)) {
// The ship ran over something collectable
node.collect();
}
}
}
}
int _chunk = 0;
void addObjects() {
while (_scroll + _chunkSpacing >= _chunk * _chunkSpacing) {
addLevelChunk(
_chunk,
-_chunk * _chunkSpacing - _chunkSpacing);
_chunk += 1;
}
}
void addLevelChunk(int chunk, double yPos) {
int level = chunk ~/ _chunksPerLevel;
int part = chunk % _chunksPerLevel;
if (part == 0) {
LevelLabel lbl = new LevelLabel(_objectFactory, level + 1);
lbl.position = new Point(0.0, yPos + _chunkSpacing / 2.0 - 150.0);
_level.addChild(lbl);
} else if (part == 1) {
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
} else if (part == 2) {
_objectFactory.addEnemyScoutSwarm(4 + level * 2, yPos);
} else if (part == 3) {
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
} else if (part == 4) {
_objectFactory.addEnemyDestroyerSwarm(2 + level, yPos);
} else if (part == 5) {
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
} else if (part == 6) {
_objectFactory.addEnemyScoutSwarm(4 + level * 2, yPos);
} else if (part == 7) {
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
} else if (part == 8) {
_objectFactory.addBossFight(level, yPos);
}
}
void fire() {
int laserLevel = _objectFactory.playerState.laserLevel;
Laser shot0 = new Laser(_objectFactory, laserLevel, -90.0);
shot0.position = _level.ship.position + new Offset(17.0, -10.0);
_level.addChild(shot0);
Laser shot1 = new Laser(_objectFactory, laserLevel, -90.0);
shot1.position = _level.ship.position + new Offset(-17.0, -10.0);
_level.addChild(shot1);
if (_playerState.sideLaserActive) {
Laser shot2 = new Laser(_objectFactory, laserLevel, -45.0);
shot2.position = _level.ship.position + new Offset(17.0, -10.0);
_level.addChild(shot2);
Laser shot3 = new Laser(_objectFactory, laserLevel, -135.0);
shot3.position = _level.ship.position + new Offset(-17.0, -10.0);
_level.addChild(shot3);
}
_effectPlayer.play(_sounds["laser"]);
}
void killShip() {
// Hide ship
_level.ship.visible = false;
_effectPlayer.play(_sounds["explosion"]);
// Add explosion
ExplosionBig explo = new ExplosionBig(_spritesGame);
explo.scale = 1.5;
explo.position = _level.ship.position;
_level.addChild(explo);
// Add flash
Flash flash = new Flash(size, 1.0);
addChild(flash);
// Set the state to game over
_gameOver = true;
// Return to main scene and report the score back in 2 seconds
new Timer(new Duration(seconds: 2), () { _gameOverCallback(_playerState.score); });
}
}
class Level extends Node {
Level() {
position = new Point(160.0, 0.0);
}
Ship ship;
double scroll(double scrollSpeed) {
position += new Offset(0.0, scrollSpeed);
return position.y;
}
}
part of game;
class GameObjectFactory {
GameObjectFactory(this.sheet, this.sounds, this.level, this.playerState);
SpriteSheet sheet;
Map<String,SoundEffect> sounds;
Level level;
PlayerState playerState;
void addAsteroids(int numAsteroids, double yPos, double distribution) {
for (int i = 0; i < numAsteroids; i++) {
GameObject obj;
if (i == 0)
obj = new AsteroidPowerUp(this);
else if (randomDouble() < distribution)
obj = new AsteroidBig(this);
else
obj = new AsteroidSmall(this);
Point pos = new Point(randomSignedDouble() * 160.0,
yPos + _chunkSpacing * randomDouble());
addGameObject(obj, pos);
}
}
void addEnemyScoutSwarm(int numEnemies, double yPos) {
for (int i = 0; i < numEnemies; i++) {
double spacing = math.max(_chunkSpacing / (numEnemies + 1.0), 80.0);
double y = yPos + _chunkSpacing / 2.0 - (numEnemies - 1) * spacing / 2.0 + i * spacing;
addGameObject(new EnemyScout(this), new Point(0.0, y));
}
}
void addEnemyDestroyerSwarm(int numEnemies, double yPos) {
for (int i = 0; i < numEnemies; i++) {
addGameObject(new EnemyDestroyer(this), new Point(randomSignedDouble() * 120.0 , yPos + _chunkSpacing * randomDouble()));
}
}
void addGameObject(GameObject obj, Point pos) {
obj.position = pos;
obj.setupActions();
level.addChild(obj);
}
void addBossFight(int l, double yPos) {
// Add boss
EnemyBoss boss = new EnemyBoss(this);
Point pos = new Point(0.0, yPos + _chunkSpacing / 2.0);
addGameObject(boss, pos);
playerState.boss = boss;
// Add boss's helpers
if (l >= 1) {
EnemyDestroyer destroyer0 = new EnemyDestroyer(this);
addGameObject(destroyer0, new Point(-80.0, yPos + _chunkSpacing / 2.0 + 70.0));
EnemyDestroyer destroyer1 = new EnemyDestroyer(this);
addGameObject(destroyer1, new Point(80.0, yPos + _chunkSpacing / 2.0 + 70.0));
if (l >= 2) {
EnemyDestroyer destroyer0 = new EnemyDestroyer(this);
addGameObject(destroyer0, new Point(-80.0, yPos + _chunkSpacing / 2.0 - 70.0));
EnemyDestroyer destroyer1 = new EnemyDestroyer(this);
addGameObject(destroyer1, new Point(80.0, yPos + _chunkSpacing / 2.0 - 70.0));
}
}
}
}
This diff is collapsed.
// 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);
}
}
part of game;
class PlayerState extends Node {
PlayerState(this._sheetUI, this._sheetGame) {
// Score display
_spriteBackgroundScore = new Sprite(_sheetUI["scoreboard.png"]);
_spriteBackgroundScore.pivot = new Point(1.0, 0.0);
_spriteBackgroundScore.scale = 0.35;
_spriteBackgroundScore.position = new Point(240.0, 10.0);
addChild(_spriteBackgroundScore);
_scoreDisplay = new ScoreDisplay(_sheetUI);
_scoreDisplay.position = new Point(-13.0, 49.0);
_spriteBackgroundScore.addChild(_scoreDisplay);
// Coin display
_spriteBackgroundCoins = new Sprite(_sheetUI["coinboard.png"]);
_spriteBackgroundCoins.pivot = new Point(1.0, 0.0);
_spriteBackgroundCoins.scale = 0.35;
_spriteBackgroundCoins.position = new Point(105.0, 10.0);
addChild(_spriteBackgroundCoins);
_coinDisplay = new ScoreDisplay(_sheetUI);
_coinDisplay.position = new Point(-13.0, 49.0);
_spriteBackgroundCoins.addChild(_coinDisplay);
}
final SpriteSheet _sheetUI;
final SpriteSheet _sheetGame;
int laserLevel = 0;
static const double normalScrollSpeed = 2.0;
double scrollSpeed = normalScrollSpeed;
double _scrollSpeedTarget = normalScrollSpeed;
EnemyBoss boss;
Sprite _spriteBackgroundScore;
ScoreDisplay _scoreDisplay;
Sprite _spriteBackgroundCoins;
ScoreDisplay _coinDisplay;
int get score => _scoreDisplay.score;
set score(int score) {
_scoreDisplay.score = score;
flashBackgroundSprite(_spriteBackgroundScore);
}
int get coins => _coinDisplay.score;
void addCoin(Coin c) {
// Animate coin to the top of the screen
Point startPos = convertPointFromNode(Point.origin, c);
Point finalPos = new Point(30.0, 30.0);
Point middlePos = new Point((startPos.x + finalPos.x) / 2.0 + 50.0,
(startPos.y + finalPos.y) / 2.0);
List<Point> path = <Point>[startPos, middlePos, finalPos];
Sprite sprite = new Sprite(_sheetGame["coin.png"]);
sprite.scale = 0.7;
ActionSpline spline = new ActionSpline((Point a) { sprite.position = a; }, path, 0.5);
spline.tension = 0.25;
ActionTween rotate = new ActionTween((double a) { sprite.rotation = a; }, 0.0, 360.0, 0.5);
ActionTween scale = new ActionTween((double a) { sprite.scale = a; }, 0.7, 1.2, 0.5);
ActionGroup group = new ActionGroup(<Action>[spline, rotate, scale]);
sprite.actions.run(new ActionSequence(<Action>[
group,
new ActionRemoveNode(sprite),
new ActionCallFunction(() {
_coinDisplay.score += 1;
flashBackgroundSprite(_spriteBackgroundCoins);
})
]));
addChild(sprite);
}
void activatePowerUp(PowerUpType type) {
if (type == PowerUpType.shield) {
_shieldFrames += 300;
} else if (type == PowerUpType.sideLaser) {
_sideLaserFrames += 300;
} else if (type == PowerUpType.speedLaser) {
_speedLaserFrames += 300;
} else if (type == PowerUpType.speedBoost) {
_speedBoostFrames += 150;
}
}
int _shieldFrames = 0;
bool get shieldActive => _shieldFrames > 0 || _speedBoostFrames > 0;
bool get shieldDeactivating =>
math.max(_shieldFrames, _speedBoostFrames) > 0 && math.max(_shieldFrames, _speedBoostFrames) < 60;
int _sideLaserFrames = 0;
bool get sideLaserActive => _sideLaserFrames > 0;
int _speedLaserFrames = 0;
bool get speedLaserActive => _speedLaserFrames > 0;
int _speedBoostFrames = 0;
bool get speedBoostActive => _speedBoostFrames > 0;
void flashBackgroundSprite(Sprite sprite) {
sprite.actions.stopAll();
ActionTween flash = new ActionTween(
(Color a) { sprite.colorOverlay = a; },
new Color(0x66ccfff0),
new Color(0x00ccfff0),
0.3);
sprite.actions.run(flash);
}
void update(double dt) {
if (_shieldFrames > 0)
_shieldFrames--;
if (_sideLaserFrames > 0)
_sideLaserFrames--;
if (_speedLaserFrames > 0)
_speedLaserFrames--;
if (_speedBoostFrames > 0)
_speedBoostFrames--;
// Update speed
if (boss != null) {
Point globalBossPos = boss.convertPointToBoxSpace(Point.origin);
if (globalBossPos.y > (_gameSizeHeight - 400.0))
_scrollSpeedTarget = 0.0;
else
_scrollSpeedTarget = normalScrollSpeed;
} else {
if (speedBoostActive)
_scrollSpeedTarget = normalScrollSpeed * 6.0;
else
_scrollSpeedTarget = normalScrollSpeed;
}
scrollSpeed = GameMath.filter(scrollSpeed, _scrollSpeedTarget, 0.1);
}
}
class ScoreDisplay extends Node {
ScoreDisplay(this._sheetUI);
int _score = 0;
int get score => _score;
set score(int score) {
_score = score;
_dirtyScore = true;
}
SpriteSheet _sheetUI;
bool _dirtyScore = true;
void update(double dt) {
if (_dirtyScore) {
removeAllChildren();
String scoreStr = _score.toString();
double xPos = -37.0;
for (int i = scoreStr.length - 1; i >= 0; i--) {
String numStr = scoreStr.substring(i, i + 1);
Sprite numSprite = new Sprite(_sheetUI["number_$numStr.png"]);
numSprite.position = new Point(xPos, 0.0);
addChild(numSprite);
xPos -= 37.0;
}
_dirtyScore = false;
}
}
}
part of game;
class PowerBar extends NodeWithSize {
PowerBar(Size size, [this.power = 1.0]) : super(size);
double power;
Paint _paintFill = new Paint()
..color = new Color(0xffffffff);
Paint _paintOutline = new Paint()
..color = new Color(0xffffffff)
..strokeWidth = 1.0
..style = ui.PaintingStyle.stroke;
void paint(PaintingCanvas canvas) {
applyTransformForPivot(canvas);
canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, size.width - 0.0, size.height - 0.0), _paintOutline);
canvas.drawRect(new Rect.fromLTRB(2.0, 2.0, (size.width - 2.0) * power, size.height - 2.0), _paintFill);
}
}
part of game;
class RepeatedImage extends Node {
Sprite _sprite0;
Sprite _sprite1;
RepeatedImage(ui.Image image, [ui.TransferMode mode = null]) {
_sprite0 = new Sprite.fromImage(image);
_sprite0.size = new Size(1024.0, 1024.0);
_sprite0.pivot = Point.origin;
_sprite1 = new Sprite.fromImage(image);
_sprite1.size = new Size(1024.0, 1024.0);
_sprite1.pivot = Point.origin;
_sprite1.position = new Point(0.0, -1024.0);
if (mode != null) {
_sprite0.transferMode = mode;
_sprite1.transferMode = mode;
}
addChild(_sprite0);
addChild(_sprite1);
}
void move(double dy) {
double yPos = (position.y + dy) % 1024.0;
position = new Point(0.0, yPos);
}
}
part of game;
class StarField extends NodeWithSize {
ui.Image _image;
SpriteSheet _spriteSheet;
int _numStars;
bool _autoScroll;
List<Point> _starPositions;
List<double> _starScales;
List<Rect> _rects;
List<Color> _colors;
final double _padding = 50.0;
Size _paddedSize = Size.zero;
Paint _paint = new Paint()
..filterQuality = ui.FilterQuality.low
..isAntiAlias = false
..transferMode = ui.TransferMode.plus;
StarField(this._spriteSheet, this._numStars, [this._autoScroll = false]) : super(Size.zero) {
_image = _spriteSheet.image;
}
void addStars() {
_starPositions = <Point>[];
_starScales = <double>[];
_colors = <Color>[];
_rects = <Rect>[];
size = spriteBox.visibleArea.size;
_paddedSize = new Size(size.width + _padding * 2.0,
size.height + _padding * 2.0);
for (int i = 0; i < _numStars; i++) {
_starPositions.add(new Point(randomDouble() * _paddedSize.width,
randomDouble() * _paddedSize.height));
_starScales.add(randomDouble() * 0.4);
_colors.add(new Color.fromARGB((255.0 * (randomDouble() * 0.5 + 0.5)).toInt(), 255, 255, 255));
_rects.add(_spriteSheet["star_${randomInt(2)}.png"].frame);
}
}
void spriteBoxPerformedLayout() {
addStars();
}
void paint(PaintingCanvas canvas) {
// Create a transform for each star
List<ui.RSTransform> transforms = <ui.RSTransform>[];
for (int i = 0; i < _numStars; i++) {
ui.RSTransform transform = new ui.RSTransform(
_starScales[i],
0.0,
_starPositions[i].x - _padding,
_starPositions[i].y - _padding);
transforms.add(transform);
}
// Draw the stars
canvas.drawAtlas(_image, transforms, _rects, _colors, ui.TransferMode.modulate, null, _paint);
}
void move(double dx, double dy) {
for (int i = 0; i < _numStars; i++) {
double xPos = _starPositions[i].x;
double yPos = _starPositions[i].y;
double scale = _starScales[i];
xPos += dx * scale;
yPos += dy * scale;
if (xPos >= _paddedSize.width) xPos -= _paddedSize.width;
if (xPos < 0) xPos += _paddedSize.width;
if (yPos >= _paddedSize.height) yPos -= _paddedSize.height;
if (yPos < 0) yPos += _paddedSize.height;
_starPositions[i] = new Point(xPos, yPos);
}
}
void update(double dt) {
if (_autoScroll) {
move(0.0, dt * 100.0);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>game_app</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.domokit.sky.asteroids</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Asteroids</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.6</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 The Chromium Authors. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>sky_mac</string>
<key>NSPrincipalClass</key>
<string>SkyApplication</string>
</dict>
</plist>
This diff is collapsed.
name: asteroids
dependencies:
flutter:
path: ../../packages/flutter
flutter_sprites:
path: ../../packages/flutter_sprites
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _bundle = _initBundle();
ImageMap _images;
SpriteSheet _spriteSheet;
TestBedApp _app;
main() async {
_images = new ImageMap(_bundle);
await _images.load(<String>[
'assets/sprites.png'
]);
String json = await _bundle.loadString('assets/sprites.json');
_spriteSheet = new SpriteSheet(_images['assets/sprites.png'], json);
_app = new TestBedApp();
runApp(_app);
}
class TestBedApp extends MaterialApp {
Widget build() {
ThemeData theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.purple
);
return new Theme(
data: theme,
child: new Title(
title: 'Test Bed',
child: new SpriteWidget(
new TestBed(),
SpriteBoxTransformMode.letterbox
)
)
);
}
}
class TestBed extends NodeWithSize {
TestBed() : super(new Size(1024.0, 1024.0));
}
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _bundle = _initBundle();
ImageMap _images;
SpriteSheet _spriteSheet;
final ThemeData _theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.purple
);
main() async {
_images = new ImageMap(_bundle);
await _images.load(<String>[
'assets/sprites.png'
]);
String json = await _bundle.loadString('assets/sprites.json');
_spriteSheet = new SpriteSheet(_images['assets/sprites.png'], json);
runApp(new MaterialApp(
title: 'Test drawAtlas',
theme: _theme,
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
return new SpriteWidget(
new TestDrawAtlas(),
SpriteBoxTransformMode.fixedWidth
);
}
}
));
}
class TestDrawAtlas extends NodeWithSize {
TestDrawAtlas() : super(new Size(1024.0, 1024.0));
void paint(PaintingCanvas canvas) {
List<RSTransform> transforms = <RSTransform>[
new RSTransform(1.0, 0.0, 100.0, 100.0)
];
List<Rect> rects = <Rect>[
_spriteSheet["ship.png"].frame
];
List<Color> colors = <Color>[
new Color(0xffffffff)
];
canvas.drawAtlas(
_spriteSheet.image,
transforms,
rects,
colors,
TransferMode.src,
null,
new Paint()
..filterQuality = FilterQuality.low
..isAntiAlias = false
);
}
}
import 'dart:ui' as ui;
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _bundle = _initBundle();
ImageMap _images;
SpriteSheet _spriteSheet;
final ThemeData _theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.purple
);
main() async {
_images = new ImageMap(_bundle);
await _images.load(<String>[
'assets/sprites.png'
]);
String json = await _bundle.loadString('assets/sprites.json');
_spriteSheet = new SpriteSheet(_images['assets/sprites.png'], json);
runApp(new MaterialApp(
title: 'Test Sprite Performance',
theme: _theme,
routes: <String, RouteBuilder>{
'/': (RouteArguments args) => new SpriteWidget(new TestPerformance())
}
));
}
class TestPerformance extends NodeWithSize {
TestPerformance() : super(new Size(1024.0, 1024.0));
final int numFramesPerTest = 100;
final int numTests = 5;
int test = 0;
int frame = 0;
int testStartTime;
void update(double dt) {
if (frame % numFramesPerTest == 0) {
if (test > 0 && test <= numTests) {
// End last test
int currentTime = new DateTime.now().millisecondsSinceEpoch;
int totalTestTime = currentTime - testStartTime;
double millisPerFrame =
totalTestTime.toDouble() / numFramesPerTest.toDouble();
print(" - RESULT fps: ${(1.0 / (millisPerFrame / 1000)).toStringAsFixed(1)} millis/frame: ${millisPerFrame.round()}");
// Clear test
removeAllChildren();
}
if (test < numTests) {
// Start new test
PerformanceTest perfTest = createTest(test);
addChild(perfTest);
print("TEST ${test + 1}/$numTests STARTING: ${perfTest.name}");
testStartTime = new DateTime.now().millisecondsSinceEpoch;
}
test++;
}
frame++;
}
PerformanceTest createTest(int n) {
if (test == 0) {
// Test atlas performance
return new TestPerformanceAtlas();
} else if (test == 1) {
// Test atlas performance
return new TestPerformanceAtlas2();
} else if (test == 2) {
// Test sprite performance
return new TestPerformanceSprites();
} else if (test == 3) {
// Test sprite performance
return new TestPerformanceSprites2();
} else if (test == 4) {
// Test particle performance
return new TestPerformanceParticles();
}
return null;
}
}
abstract class PerformanceTest extends Node {
String get name;
}
class TestPerformanceParticles extends PerformanceTest {
String get name => "64 particle systems";
final grid = 8;
TestPerformanceParticles() {
for (int x = 0; x < grid; x++) {
for (int y = 0; y < grid; y++) {
ParticleSystem particles = new ParticleSystem(
_spriteSheet["explosion_particle.png"],
rotateToMovement: true,
startRotation:90.0,
startRotationVar: 0.0,
endRotation: 90.0,
startSize: 0.3,
startSizeVar: 0.1,
endSize: 0.3,
endSizeVar: 0.1,
emissionRate:100.0,
greenVar: 127,
redVar: 127
);
particles.position = new Point(x * 1024.0 / (grid - 1), y * 1024.0 / (grid - 1));
addChild(particles);
}
}
}
}
class TestPerformanceSprites extends PerformanceTest {
String get name => "1001 sprites (24% offscreen)";
final int grid = 100;
TestPerformanceSprites() {
for (int x = 0; x < grid; x++) {
for (int y = 0; y < grid; y++) {
Sprite sprite = new Sprite(_spriteSheet["asteroid_big_1.png"]);
sprite.scale = 1.0;
sprite.position = new Point(x * 1024.0 / (grid - 1), y * 1024.0 / (grid - 1));
addChild(sprite);
}
}
Sprite sprite = new Sprite(_spriteSheet["asteroid_big_1.png"]);
sprite.position = new Point(512.0, 512.0);
addChild(sprite);
}
void update(double dt) {
for (Node child in children) {
final Sprite sprite = child;
sprite.rotation += 1;
}
}
}
class TestPerformanceSprites2 extends PerformanceTest {
String get name => "1001 sprites (24% offscreen never added)";
final int grid = 100;
TestPerformanceSprites2() {
for (int x = 12; x < grid - 12; x++) {
for (int y = 0; y < grid; y++) {
Sprite sprite = new Sprite(_spriteSheet["asteroid_big_1.png"]);
sprite.scale = 1.0;
sprite.position = new Point(x * 1024.0 / (grid - 1), y * 1024.0 / (grid - 1));
addChild(sprite);
}
}
Sprite sprite = new Sprite(_spriteSheet["asteroid_big_1.png"]);
sprite.position = new Point(512.0, 512.0);
addChild(sprite);
}
void update(double dt) {
for (Node child in children) {
final Sprite sprite = child;
sprite.rotation += 1;
}
}
}
class TestPerformanceAtlas extends PerformanceTest {
String get name => "1001 rects drawAtlas (24% offscreen)";
final int grid = 100;
double rotation = 0.0;
List<Rect> rects = <Rect>[];
Paint cachedPaint = new Paint()
..filterQuality = ui.FilterQuality.low
..isAntiAlias = false;
TestPerformanceAtlas() {
for (int x = 0; x < grid; x++) {
for (int y = 0; y < grid; y++) {
rects.add(_spriteSheet["asteroid_big_1.png"].frame);
}
}
rects.add(_spriteSheet["asteroid_big_1.png"].frame);
}
void paint(PaintingCanvas canvas) {
// Setup transforms
List<ui.RSTransform> transforms = <ui.RSTransform>[];
for (int x = 0; x < grid; x++) {
for (int y = 0; y < grid; y++) {
double xPos = x * 1024.0 / (grid - 1);
double yPos = y * 1024.0 / (grid - 1);
transforms.add(createTransform(xPos, yPos, rects[0].size.width / 2.0, rects[0].size.height / 2.0, rotation, 1.0));
}
}
transforms.add(createTransform(512.0, 512.0, rects[0].size.width / 2.0, rects[0].size.height / 2.0, rotation, 1.0));
// Draw atlas
Rect cullRect = spriteBox.visibleArea;
canvas.drawAtlas(_spriteSheet.image, transforms, rects, null, null, cullRect, cachedPaint);
}
void update(double dt) {
rotation += 1.0;
}
ui.RSTransform createTransform(double x, double y, double ax, double ay, double rot, double scale) {
double scos = math.cos(convertDegrees2Radians(rot)) * scale;
double ssin = math.sin(convertDegrees2Radians(rot)) * scale;
double tx = x + -scos * ax + ssin * ay;
double ty = y + -ssin * ax - scos * ay;
return new ui.RSTransform(scos, ssin, tx, ty);
}
}
class TestPerformanceAtlas2 extends PerformanceTest {
String get name => "1001 rects drawAtlas (24% offscreen never added)";
final int grid = 100;
double rotation = 0.0;
List<Rect> rects = <Rect>[];
Paint cachedPaint = new Paint()
..filterQuality = ui.FilterQuality.low
..isAntiAlias = false;
TestPerformanceAtlas2() {
for (int x = 12; x < grid - 12; x++) {
for (int y = 0; y < grid; y++) {
rects.add(_spriteSheet["asteroid_big_1.png"].frame);
}
}
rects.add(_spriteSheet["asteroid_big_1.png"].frame);
}
void paint(PaintingCanvas canvas) {
// Setup transforms
List<ui.RSTransform> transforms = <ui.RSTransform>[];
for (int x = 12; x < grid - 12; x++) {
for (int y = 0; y < grid; y++) {
double xPos = x * 1024.0 / (grid - 1);
double yPos = y * 1024.0 / (grid - 1);
transforms.add(createTransform(xPos, yPos, rects[0].size.width / 2.0, rects[0].size.height / 2.0, rotation, 1.0));
}
}
transforms.add(createTransform(512.0, 512.0, rects[0].size.width / 2.0, rects[0].size.height / 2.0, rotation, 1.0));
// Draw atlas
Rect cullRect = spriteBox.visibleArea;
canvas.drawAtlas(_spriteSheet.image, transforms, rects, null, null, cullRect, cachedPaint);
}
void update(double dt) {
rotation += 1.0;
}
ui.RSTransform createTransform(double x, double y, double ax, double ay, double rot, double scale) {
double scos = math.cos(convertDegrees2Radians(rot)) * scale;
double ssin = math.sin(convertDegrees2Radians(rot)) * scale;
double tx = x + -scos * ax + ssin * ay;
double ty = y + -ssin * ax - scos * ay;
return new ui.RSTransform(scos, ssin, tx, ty);
}
}
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:vector_math/vector_math_64.dart';
main() {
runTest();
}
const int numSystems = 1000;
const int numFrames = 1000;
void runTest() {
int timeStart;
timeStart = new DateTime.now().millisecondsSinceEpoch;
// Create systems
List<TestParticleSystem> systems = <TestParticleSystem>[];
for (int i = 0; i < numSystems; i++)
systems.add(new TestParticleSystem());
int timeAfterCreate = new DateTime.now().millisecondsSinceEpoch;
print("TIME creation ${(timeAfterCreate - timeStart) / 1000.0}");
timeStart = new DateTime.now().millisecondsSinceEpoch;
// Update systems
for (int frame = 0; frame < numFrames; frame++) {
for (int i = 0; i < numSystems; i++) {
systems[i].update(1.0 / 60.0);
}
}
int timeAfterUpdates = new DateTime.now().millisecondsSinceEpoch;
print("TIME updates ${(timeAfterUpdates - timeStart) / 1000.0}");
timeStart = new DateTime.now().millisecondsSinceEpoch;
// Calculate matrices
for (int frame = 0; frame < numFrames; frame++) {
for (int i = 0; i < numSystems; i++) {
systems[i].paint();
}
}
int timeAfterMatrices = new DateTime.now().millisecondsSinceEpoch;
print("TIME matrices ${(timeAfterMatrices - timeStart) / 1000.0}");
}
class TestParticle {
Vector2 pos;
Vector2 startPos;
double colorPos;
double deltaColorPos;
double size;
double deltaSize;
double rotation;
double deltaRotation;
double timeToLive;
Vector2 dir;
double radialAccel;
double tangentialAccel;
Float64List simpleColorSequence;
Matrix4 transform;
}
class TestParticleSystem {
double life;
double lifeVar;
Vector2 posVar;
double startSize;
double startSizeVar;
double endSize;
double endSizeVar;
double startRotation;
double startRotationVar;
double endRotation;
double endRotationVar;
double direction;
double directionVar;
double speed;
double speedVar;
double radialAcceleration;
double radialAccelerationVar;
double tangentialAcceleration;
double tangentialAccelerationVar;
Vector2 gravity;
int maxParticles;
int numParticlesToEmit;
double emissionRate;
List<TestParticle> _particles;
double _emitCounter;
int _numEmittedParticles = 0;
TestParticleSystem({this.life: 1.5,
this.lifeVar: 0.0,
this.startSize: 2.5,
this.startSizeVar: 0.5,
this.endSize: 0.0,
this.endSizeVar: 0.0,
this.startRotation: 0.0,
this.startRotationVar: 0.0,
this.endRotation: 0.0,
this.endRotationVar: 0.0,
this.direction: 0.0,
this.directionVar: 360.0,
this.speed: 100.0,
this.speedVar: 50.0,
this.radialAcceleration: 0.0,
this.radialAccelerationVar: 0.0,
this.tangentialAcceleration: 0.0,
this.tangentialAccelerationVar: 0.0,
this.gravity,
this.maxParticles: 100,
this.emissionRate: 50.0,
this.numParticlesToEmit: 0}) {
posVar = new Vector2.zero();
_particles = new List<TestParticle>();
_emitCounter = 0.0;
gravity = new Vector2.zero();
}
void update(double dt) {
// Create new particles
double rate = 1.0 / emissionRate;
if (_particles.length < maxParticles) {
_emitCounter += dt;
}
while (_particles.length < maxParticles
&& _emitCounter > rate
&& (numParticlesToEmit == 0 || _numEmittedParticles < numParticlesToEmit)) {
// Add a new particle
_addParticle();
_emitCounter -= rate;
}
// Iterate over all particles
for (int i = _particles.length -1; i >= 0; i--) {
TestParticle particle = _particles[i];
// Manage life time
particle.timeToLive -= dt;
if (particle.timeToLive <= 0) {
_particles.removeAt(i);
continue;
}
// Update the particle
// Radial acceleration
Vector2 radial;
if (particle.pos[0] != 0 || particle.pos[1] != 0) {
radial = new Vector2.copy(particle.pos).normalize();
} else {
radial = new Vector2.zero();
}
Vector2 tangential = new Vector2.copy(radial);
radial.scale(particle.radialAccel);
// Tangential acceleration
double newY = tangential.x;
tangential.x = -tangential.y;
tangential.y = newY;
tangential.scale(particle.tangentialAccel);
// (gravity + radial + tangential) * dt
Vector2 accel = (gravity + radial + tangential).scale(dt);
particle.dir += accel;
// Update particle position
particle.pos[0] += particle.dir[0] * dt;
particle.pos[1] += particle.dir[1] * dt;
// Size
particle.size = math.max(particle.size + particle.deltaSize * dt, 0.0);
// Angle
particle.rotation += particle.deltaRotation * dt;
// Color
if (particle.simpleColorSequence != null) {
for (int i = 0; i < 4; i++) {
particle.simpleColorSequence[i] += particle.simpleColorSequence[i + 4] * dt;
}
} else {
particle.colorPos = math.min(particle.colorPos + particle.deltaColorPos * dt, 1.0);
}
}
}
void _addParticle() {
TestParticle particle = new TestParticle();
// Time to live
particle.timeToLive = math.max(life + lifeVar * randomSignedDouble(), 0.0);
// Position
Vector2 srcPos = new Vector2.zero();
particle.pos = new Vector2(srcPos.x + posVar.x * randomSignedDouble(),
srcPos.y + posVar.y * randomSignedDouble());
// Size
particle.size = math.max(startSize + startSizeVar * randomSignedDouble(), 0.0);
double endSizeFinal = math.max(endSize + endSizeVar * randomSignedDouble(), 0.0);
particle.deltaSize = (endSizeFinal - particle.size) / particle.timeToLive;
// Rotation
particle.rotation = startRotation + startRotationVar * randomSignedDouble();
double endRotationFinal = endRotation + endRotationVar * randomSignedDouble();
particle.deltaRotation = (endRotationFinal - particle.rotation) / particle.timeToLive;
// Direction
double dirRadians = radians(direction + directionVar * randomSignedDouble());
Vector2 dirVector = new Vector2(math.cos(dirRadians), math.sin(dirRadians));
double speedFinal = speed + speedVar * randomSignedDouble();
particle.dir = dirVector.scale(speedFinal);
// Radial acceleration
particle.radialAccel = radialAcceleration + radialAccelerationVar * randomSignedDouble();
// Tangential acceleration
particle.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randomSignedDouble();
// Colors
particle.simpleColorSequence = new Float64List(8);
particle.simpleColorSequence[0] = 255.0;
particle.simpleColorSequence[1] = 255.0;
particle.simpleColorSequence[2] = 255.0;
particle.simpleColorSequence[3] = 255.0;
particle.simpleColorSequence[4] = 255.0;
particle.simpleColorSequence[5] = 0.0;
particle.simpleColorSequence[6] = 0.0;
particle.simpleColorSequence[7] = 0.0;
// Transform
particle.transform = new Matrix4.identity();
// Add particle
_particles.add(particle);
_numEmittedParticles++;
}
void paint() {
if (!printed) {
printed = true;
}
for (int i = _particles.length -1; i >= 0; i--) {
TestParticle particle = _particles[i];
particle.rotation + randomSignedDouble();
// Transform
double c = math.cos(radians(particle.rotation));
double s = math.sin(radians(particle.rotation));
// Create transformation matrix for scale, position and rotation
Matrix4 matrix = new Matrix4(c * particle.size, s * particle.size, 0.0, 0.0,
-s * particle.size, c * particle.size, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
particle.pos.x, particle.pos.y, 0.0, 1.0);
particle.transform.multiply(matrix);
}
}
}
math.Random _random = new math.Random();
bool printed = false;
// Random methods
double randomDouble() {
return _random.nextDouble();
}
double randomSignedDouble() {
return _random.nextDouble() * 2.0 - 1.0;
}
int randomInt(int max) {
return _random.nextInt(max);
}
import 'dart:ui';
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _bundle = _initBundle();
ImageMap _images;
SpriteSheet _spriteSheet;
main() async {
_images = new ImageMap(_bundle);
await _images.load(<String>[
'assets/sprites.png'
]);
String json = await _bundle.loadString('assets/sprites.json');
_spriteSheet = new SpriteSheet(_images['assets/sprites.png'], json);
runApp(new MaterialApp(
title: 'Test Physics',
theme: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.purple
),
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
return new SpriteWidget(
new TestBed(),
SpriteBoxTransformMode.letterbox
);
}
}
));
}
class TestBed extends NodeWithSize {
Sprite _obstacle;
PhysicsWorld _world;
PhysicsGroup _group;
PhysicsGroup _group2;
TestBed() : super(new Size(1024.0, 1024.0)) {
_world = new PhysicsWorld(new Offset(0.0, 100.0));
_world.drawDebug = true;
_group = new PhysicsGroup();
_group2 = new PhysicsGroup();
_group2.position = new Point(50.0, 50.0);
_world.addChild(_group);
_world.addChild(_group2);
_obstacle = new Sprite(_spriteSheet["ship.png"]);
_obstacle.position = new Point(512.0, 800.0);
_obstacle.size = new Size(64.0, 64.0);
_obstacle.scale = 2.0;
_obstacle.physicsBody = new PhysicsBody(
new PhysicsShapeCircle(Point.origin, 32.0),
type: PhysicsBodyType.static,
friction: 0.5,
tag: "obstacle"
);
_group.addChild(_obstacle);
_world.addContactCallback(myCallback, "obstacle", "ship", PhysicsContactType.begin);
// Animate group
ActionSequence seq = new ActionSequence(<Action>[
new ActionTween((Point a) { _group.position = a; }, new Point(-256.0, 0.0), new Point(256.0, 0.0), 1.0, Curves.easeInOut),
new ActionTween((Point a) { _group.position = a; }, new Point(256.0, 0.0), new Point(-256.0, 0.0), 1.0, Curves.easeInOut)
]);
_group.actions.run(new ActionRepeatForever(seq));
addChild(_world);
userInteractionEnabled = true;
}
void myCallback(PhysicsContactType type, PhysicsContact contact) {
}
bool handleEvent(SpriteBoxEvent event) {
if (event.type == "pointerdown") {
Point pos = convertPointToNodeSpace(event.boxPosition);
PhysicsGroup group = new PhysicsGroup();
group.position = pos;
_world.addChild(group);
Sprite shipA;
shipA = new Sprite(_spriteSheet["ship.png"]);
shipA.opacity = 0.3;
shipA.position = new Point(-40.0, 0.0);
shipA.size = new Size(64.0, 64.0);
shipA.physicsBody = new PhysicsBody(new PhysicsShapeCircle(Point.origin, 32.0),
friction: 0.5,
restitution: 0.5,
tag: "ship"
);
group.addChild(shipA);
Sprite shipB;
shipB = new Sprite(_spriteSheet["ship.png"]);
shipB.opacity = 0.3;
shipB.position = new Point(40.0, 0.0);
shipB.size = new Size(64.0, 64.0);
shipB.physicsBody = new PhysicsBody(new PhysicsShapePolygon(<Point>[new Point(-25.0, -25.0), new Point(25.0, -25.0), new Point(25.0, 25.0), new Point(-25.0, 25.0)]),
friction: 0.5,
restitution: 0.5,
tag: "ship"
);
group.addChild(shipB);
}
return true;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment