Files
star_taxi_apk_test/lib/main.dart

305 lines
8.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/material.dart';
void main() {
runApp(const StarTaxiApp());
}
class StarTaxiApp extends StatelessWidget {
const StarTaxiApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Star Taxi APK Test',
theme: ThemeData.dark(useMaterial3: true),
home: const StarTaxiDemo(),
);
}
}
class StarTaxiDemo extends StatefulWidget {
const StarTaxiDemo({super.key});
@override
State<StarTaxiDemo> createState() => _StarTaxiDemoState();
}
class _StarTaxiDemoState extends State<StarTaxiDemo> {
static const int lanes = 3;
static const double playerY = 0.86;
final _rng = math.Random();
final List<_Obstacle> _obstacles = [];
Timer? _loop;
double _lane = 1;
double _speed = 0.010;
int _score = 0;
int _best = 0;
bool _running = true;
@override
void initState() {
super.initState();
_spawnInitial();
_loop = Timer.periodic(const Duration(milliseconds: 16), (_) => _tick());
}
@override
void dispose() {
_loop?.cancel();
super.dispose();
}
void _spawnInitial() {
_obstacles.clear();
for (var i = 0; i < 5; i++) {
_obstacles.add(_Obstacle(
lane: _rng.nextInt(lanes).toDouble(),
y: -0.8 - i * 0.45,
));
}
}
void _tick() {
if (!_running) return;
setState(() {
_speed = (_speed + 0.00001).clamp(0.010, 0.03);
_score += 1;
for (final o in _obstacles) {
o.y += _speed;
if (o.y > 1.15) {
o.y = -0.9 - _rng.nextDouble() * 0.8;
o.lane = _rng.nextInt(lanes).toDouble();
}
}
for (final o in _obstacles) {
if ((o.y - playerY).abs() < 0.085 && (o.lane - _lane).abs() < 0.1) {
_running = false;
_best = math.max(_best, _score);
break;
}
}
});
}
void _move(int dir) {
if (!_running) return;
setState(() {
_lane = (_lane + dir).clamp(0, lanes - 1).toDouble();
});
}
void _restart() {
setState(() {
_score = 0;
_speed = 0.010;
_lane = 1;
_running = true;
_spawnInitial();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Score: $_score', style: const TextStyle(fontSize: 20)),
Text('Best: $_best', style: const TextStyle(fontSize: 18)),
],
),
),
Expanded(
child: AspectRatio(
aspectRatio: 9 / 16,
child: Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFF0B1021), Color(0xFF1B2348)],
),
),
child: CustomPaint(
painter: _RoadPainter(
lane: _lane,
obstacles: _obstacles,
),
child: !_running
? Center(
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.65),
borderRadius: BorderRadius.circular(12),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Crash! 💥',
style: TextStyle(fontSize: 26)),
const SizedBox(height: 8),
ElevatedButton(
onPressed: _restart,
child: const Text('Nochmal'),
),
],
),
),
)
: null,
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 20),
child: Row(
children: [
Expanded(
child: FilledButton.icon(
onPressed: () => _move(-1),
icon: const Icon(Icons.arrow_left),
label: const Text('Links'),
),
),
const SizedBox(width: 12),
Expanded(
child: FilledButton.icon(
onPressed: () => _move(1),
icon: const Icon(Icons.arrow_right),
label: const Text('Rechts'),
),
),
],
),
),
const Padding(
padding: EdgeInsets.only(bottom: 10),
child: Text('Star Taxi kleines 3D-Arcade APK Testbuild'),
),
],
),
),
);
}
}
class _RoadPainter extends CustomPainter {
final double lane;
final List<_Obstacle> obstacles;
const _RoadPainter({required this.lane, required this.obstacles});
@override
void paint(Canvas canvas, Size size) {
final road = Paint()..color = const Color(0xFF2A2F40);
final line = Paint()
..color = const Color(0xAAFFFFFF)
..strokeWidth = 2;
final topWidth = size.width * 0.35;
final bottomWidth = size.width * 0.95;
final roadPath = Path()
..moveTo((size.width - topWidth) / 2, 0)
..lineTo((size.width + topWidth) / 2, 0)
..lineTo((size.width + bottomWidth) / 2, size.height)
..lineTo((size.width - bottomWidth) / 2, size.height)
..close();
canvas.drawPath(roadPath, road);
for (int i = 1; i < 3; i++) {
final t = i / 3;
final xTop = size.width / 2 + (t - 0.5) * topWidth;
final xBottom = size.width / 2 + (t - 0.5) * bottomWidth;
canvas.drawLine(Offset(xTop, 0), Offset(xBottom, size.height), line);
}
for (double y = 0; y < 1.1; y += 0.12) {
final py = y * size.height;
final w = _roadWidthAtY(size, py, topWidth, bottomWidth);
canvas.drawLine(
Offset(size.width / 2 - w * 0.04, py),
Offset(size.width / 2 + w * 0.04, py),
Paint()
..color = Colors.white.withValues(alpha: 0.35)
..strokeWidth = 2,
);
}
for (final o in obstacles) {
_drawCar(
canvas,
size,
lane: o.lane,
yNorm: o.y,
color: const Color(0xFFE26D5A),
);
}
_drawCar(
canvas,
size,
lane: lane,
yNorm: _StarTaxiDemoState.playerY,
color: const Color(0xFF3DDC97),
);
}
void _drawCar(Canvas canvas, Size size,
{required double lane, required double yNorm, required Color color}) {
final y = yNorm * size.height;
final wRoad = _roadWidthAtY(size, y, size.width * 0.35, size.width * 0.95);
final laneWidth = wRoad / 3;
final left = size.width / 2 - wRoad / 2 + lane * laneWidth + laneWidth * 0.15;
final width = laneWidth * 0.7;
final height = width * 0.9;
final rect = RRect.fromRectAndRadius(
Rect.fromLTWH(left, y - height / 2, width, height),
const Radius.circular(8),
);
canvas.drawRRect(rect, Paint()..color = color);
canvas.drawRRect(
rect,
Paint()
..style = PaintingStyle.stroke
..strokeWidth = 1.2
..color = Colors.white.withValues(alpha: 0.65),
);
}
double _roadWidthAtY(Size size, double y, double topWidth, double bottomWidth) {
final t = (y / size.height).clamp(0.0, 1.0);
return topWidth + (bottomWidth - topWidth) * t;
}
@override
bool shouldRepaint(covariant _RoadPainter oldDelegate) => true;
}
class _Obstacle {
_Obstacle({required this.lane, required this.y});
double lane;
double y;
}