This commit is contained in:
2020-01-15 21:49:59 +03:00
parent 527c6c53f6
commit 7cb49fc7a7
18 changed files with 227 additions and 46 deletions

View File

@@ -9,6 +9,3 @@
- include_role:
name: ansible-deploy
tasks_from: complete.yml
- include_role:
name: service
tasks_from: restart.yml

View File

@@ -2,7 +2,7 @@
"SdkDir": "C:\\sdk",
"BuildDir": null,
"PublishDir": "",
"PublishUrl": "https://shmyga.ru/repo/tankz",
"PublishUrl": "https://shmyga.ru/repo/puzzlez",
"Develop": false,
"Key": {
"store": "keystore.jks",

View File

@@ -5,6 +5,7 @@ const packageInfo = require('./package.json');
const {System, Sdk, Haxe, Project} = require('gulp-haxetool');
const dateformat = require('dateformat');
const argv = require('yargs').argv;
const publish = require('./tasks/gulp-publish');
if (Config.SdkDir) {
Sdk.dir = Config.SdkDir;
@@ -22,7 +23,7 @@ const config = new Project.Config({
meta: {
title: 'Puzzle\'z',
filename: 'puzzlez',
icon: 'src/icon.png',
icon: 'src/resources/icon.png',
pack: 'ru.m.puzzlez',
author: 'shmyga <shmyga.z@gmail.com>',
company: 'MegaLoMania',
@@ -54,12 +55,14 @@ const app = new Project(
],
main: 'ru.m.puzzlez.PuzzlezApp',
meta: {
width: 1024,
width: 1280,
height: 768,
},
}),
).bind(module, gulp);
module.exports.publish = publish(packageInfo.name, packageInfo.version, Config.PublishDir, Config.PublishUrl);
const defaultSeries = [
exports.clean,
module.exports['app:flash:build'],
@@ -85,4 +88,8 @@ if (System.isWindows) {
);
}
defaultSeries.push(
exports.publish,
);
module.exports.default = gulp.series(defaultSeries);

View File

@@ -1,6 +1,6 @@
{
"name": "puzzlez",
"version": "0.0.1",
"version": "0.0.2",
"private": true,
"devDependencies": {
"dateformat": "^3.0.3",

View File

@@ -0,0 +1,27 @@
package ru.m.puzzlez;
import flash.display.BitmapData;
import flash.filters.ColorMatrixFilter;
import flash.geom.Point;
import flash.Lib;
import openfl.Assets;
class LinuxIcon {
private static function prepareIcon(bitmap:BitmapData):BitmapData {
var matrix:Array<Float> = [];
matrix = matrix.concat([0, 0, 1, 0, 0]);
matrix = matrix.concat([0, 1, 0, 0, 0]);
matrix = matrix.concat([1, 0, 0, 0, 0]);
matrix = matrix.concat([0, 0, 0, 1, 0]);
var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix);
var bitmap:BitmapData = bitmap.clone();
bitmap.applyFilter(bitmap, bitmap.rect, new Point(0, 0), cmf);
return bitmap;
}
public static function apply() {
var icon = Assets.getBitmapData("resources/icon.png");
Lib.current.stage.window.setIcon(prepareIcon(icon).image);
}
}

View File

@@ -8,6 +8,9 @@ class PuzzlezApp extends App {
public static function main() {
L.push(new TraceLogger());
#if linux
LinuxIcon.apply();
#end
var app = new PuzzlezApp(new PuzzlezTheme());
app.start(new PuzzlezAppView());
L.d("Puzzlez", "started");

View File

@@ -20,14 +20,24 @@ class Game implements IGame {
}
public function start():Void {
shuffle();
signal.emit(GameEvent.START(state));
shuffle();
}
public function shuffle():Void {
for (part in state.parts) {
part.rect.x = Math.random() * (state.preset.tableRect.width - part.rect.width);
part.rect.y = Math.random() * (state.preset.tableRect.height - part.rect.height);
var bound = part.rect.width * 0.25;
part.rect.x = bound + Math.random() * (state.preset.tableRect.width - part.rect.width - bound * 2);
part.rect.y = bound + Math.random() * (state.preset.tableRect.height - part.rect.height - bound * 2);
signal.emit(GameEvent.PART_MOVED(part.id, part.rect.topLeft));
}
}
public function collect():Void {
for (part in state.parts) {
part.rect.x = part.position.x;
part.rect.y = part.position.y;
signal.emit(GameEvent.PART_MOVED(part.id, part.rect.topLeft));
}
}

View File

@@ -64,9 +64,10 @@ class GameUtil {
public static function buildPreset(image:ImageSource):GamePreset {
var size = 8;
var offset = 100;
var imageRect = new Rectangle(offset, offset, 1024, 1024);
var tableRect = new Rectangle(0, 0, imageRect.width + offset * 2, imageRect.height + offset * 2);
var offsetX = 500;
var offsetY = 200;
var imageRect = new Rectangle(offsetX, offsetY, 1024, 1024);
var tableRect = new Rectangle(0, 0, imageRect.width + offsetX * 2, imageRect.height + offsetY * 2);
return {
image:image,
grid: {width: size, height: size},

View File

@@ -8,5 +8,7 @@ interface IGame {
public function start():Void;
public function stop():Void;
public function shuffle():Void;
public function collect():Void;
public function dispose():Void;
}

View File

@@ -13,13 +13,21 @@ class PartView extends Sprite {
private function set_position(value:Point):Point {
position = value.clone();
x = position.x - (bitmap.bitmapData.width - size.x) / 2;
y = position.y - (bitmap.bitmapData.height - size.y) / 2;
refresh();
return position;
}
public var image(default, set):BitmapData;
private function set_image(value:BitmapData):BitmapData {
image = value;
bitmap.bitmapData = image;
refresh();
return image;
}
private var size:Point;
public var bitmap:Bitmap;
private var bitmap:Bitmap;
public function new(id:Int, image:BitmapData, size:Point) {
super();
@@ -29,4 +37,10 @@ class PartView extends Sprite {
addChild(bitmap);
}
private function refresh():Void {
if (position != null && image != null) {
x = position.x - (bitmap.bitmapData.width - size.x) / 2;
y = position.y - (bitmap.bitmapData.height - size.y) / 2;
}
}
}

View File

@@ -24,7 +24,7 @@ class Render extends SpriteView implements IRender {
private function set_scale(value:Float):Float {
var result = table.scaleX = table.scaleY = value;
setSize(table.width, table.height, 'table');
//setSize(table.width, table.height, 'table');
return result;
}
@@ -59,19 +59,13 @@ class Render extends SpriteView implements IRender {
private function onStart(state:GameState):Void {
clean();
this.state = state;
RenderUtil.resolveImage(state.preset.image).then(start);
}
private function start(image:BitmapData):Void {
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
for (part in state.parts) {
var partImage = RenderUtil.cropImagePart(this.image, part);
var partView = new PartView(part.id, partImage, part.rect.size);
var partView = new PartView(part.id, null, part.rect.size);
partView.position = part.rect.topLeft;
parts.set(part.id, partView);
table.addChild(partView);
}
scale = scale;
table.graphics.lineStyle(2, 0xCCCCCC);
table.graphics.beginFill(0x555555);
table.graphics.drawRect(state.preset.tableRect.x, state.preset.tableRect.y, state.preset.tableRect.width, state.preset.tableRect.height);
@@ -83,10 +77,26 @@ class Render extends SpriteView implements IRender {
table.graphics.drawRect(state.preset.imageRect.x, state.preset.imageRect.y, state.preset.imageRect.width, state.preset.imageRect.height);
table.graphics.endFill();
table.graphics.lineStyle();
RenderUtil.resolveImage(state.preset.image).then(onImageResolved);
toUpdate();
}
private function onImageResolved(image:BitmapData):Void {
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
for (part in state.parts) {
var partImage = RenderUtil.cropImagePart(this.image, part);
var partView = parts[part.id];
partView.image = partImage;
}
}
override public function update():Void {
super.update();
if (state != null) {
scale = Math.min(width / state.preset.tableRect.width, height / state.preset.tableRect.height);
}
}
private function onMouseDown(event:MouseEvent):Void {
if (Std.is(event.target, PartView)) {
activePart = event.target;
@@ -117,9 +127,9 @@ class Render extends SpriteView implements IRender {
private function save(part:PartView):Void {
var file = new FileReference();
var bitmapData = part.bitmap.bitmapData;
var image = part.image;
var data = new ByteArray();
bitmapData.encode(new Rectangle(0, 0, bitmapData.width, bitmapData.height), new PNGEncoderOptions(), data);
image.encode(new Rectangle(0, 0, image.width, image.height), new PNGEncoderOptions(), data);
file.save(data, "icon.png");
}

View File

@@ -1,11 +1,10 @@
package ru.m.puzzlez.view;
import haxework.view.form.ButtonView;
import haxework.net.JsonLoader;
import haxework.view.data.DataView;
import haxework.view.form.ButtonView;
import haxework.view.group.VGroupView;
import haxework.view.ImageView;
import haxework.view.list.ScrollBarView;
import haxework.view.utils.DrawUtil;
import openfl.utils.Assets;
import openfl.utils.AssetType;
@@ -24,16 +23,13 @@ typedef PixabayResponse = {
@:template class PuzzlezAppView extends VGroupView {
@:view private var scale:ScrollBarView;
@:view private var images:DataView<ImageSource, ImageView>;
@:view private var render:IRender;
private var game:IGame;
public function new() {
super();
images.data = [for (name in Assets.list(AssetType.IMAGE)) ASSET(name)];
render.scale = 0.75;
scale.position = render.scale - scale.ratio;
images.data = [for (name in Assets.list(AssetType.IMAGE).filter(function(name:String) return name.substr(0, 15) == "resources/image")) ASSET(name)];
}
private function imageViewFactory(index:Int, image:ImageSource):ImageView {
@@ -47,6 +43,7 @@ typedef PixabayResponse = {
private function moreImages(view:ButtonView):Void {
view.visible = false;
view.toUpdateParent();
new JsonLoader<PixabayResponse>()
.GET('https://pixabay.com/api/?key=14915210-5eae157281211e0ad28bc8def&category=nature')
.then(function(result:PixabayResponse) {
@@ -54,10 +51,6 @@ typedef PixabayResponse = {
});
}
public function setScale(value:Float):Void {
render.scale = value + scale.ratio;
}
public function start(image:ImageSource):Void {
stop();
game = new Game(GameUtil.buildPreset(image));

View File

@@ -12,6 +12,12 @@ views:
- $type: haxework.view.form.LabelView
text: Puzzle'z
font.size: 42
- $type: haxework.view.form.ButtonView
text: Shuffle
+onPress: ~game.shuffle()
- $type: haxework.view.form.ButtonView
text: Collect
+onPress: ~game.collect()
- id: images
$type: haxework.view.data.DataView
layout:
@@ -22,20 +28,17 @@ views:
+onDataSelect: ~start
geometry.margin: 5
overflow.y: scroll
- id: more
$type: haxework.view.form.ButtonView
- $type: haxework.view.form.ButtonView
text: More
+onPress: ~moreImages
- id: scale
$type: haxework.view.list.VScrollBarView
ratio: 0.5
+onScroll: ~setScale
- $type: haxework.view.group.GroupView
style: frame
geometry.width: 100%
geometry.height: 100%
overflow.x: scroll
overflow.y: scroll
overflow.x: crop
overflow.y: crop
views:
- id: render
$type: ru.m.puzzlez.render.Render
geometry.width: 100%
geometry.height: 100%

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

114
tasks/gulp-publish.js Executable file
View File

@@ -0,0 +1,114 @@
const gulp = require('gulp');
const fs = require('fs');
const fse = require('fs-extra');
const path = require('path');
const through = require('through2');
class Package {
constructor(platform, type, version, versionInt) {
this.platform = platform;
this.type = type;
this.version = version;
this.versionInt = versionInt;
}
get key() {
return [this.platform, this.type].join(':');
}
static getPlatform(filename) {
for (const [platform, r] of [
['android', /^.*?\.apk$/],
['linux', /^.*?\.deb$/],
['linux', /^.*?linux\.tar\.gz$/],
['windows', /^.*?win\.zip$/],
['windows', /^.*?\.exe$/],
]) {
if (r.test(filename)) {
return platform;
}
}
return null;
}
static getType(filename) {
for (const [type, r] of [
['apk', /^.*?\.apk$/],
['deb', /^.*?\.deb$/],
['archive', /^.*?\.tar\.gz$/],
['archive', /^.*?\.zip$/],
['exe', /^.*?\.exe$/],
]) {
if (r.test(filename)) {
return type;
}
}
return null;
}
static getVersion(filename) {
const m = /(\d+)\.(\d+)\.(\d+)/.exec(filename);
if (m) {
return [m[0], parseInt(m[1]) * 10000 + parseInt(m[2]) * 100 + parseInt(m[3])];
}
return null;
}
static parseFilename(filename) {
const platform = this.getPlatform(filename);
const type = this.getType(filename);
const version = this.getVersion(filename);
if (platform && type && version) {
return new Package(platform, type, version[0], version[1]);
}
return null;
}
}
module.exports = (name, version, publishDir, publishUrl) => function publish(cb) {
const packages = {};
fse.ensureDirSync(publishDir);
return gulp.series([
function copy() {
return gulp.src('target/client/@(android|archive|debian|installer)/*')
.pipe(through.obj(function (file, enc, cb) {
const pack = Package.parseFilename(file.path);
if (pack) {
this.push(file);
}
cb(null);
}))
.pipe(gulp.dest(publishDir))
},
function generate() {
return gulp.src(`${publishDir}/*/*`)
.pipe(through.obj(function (file, enc, cb) {
const basepath = file.path.replace(file.base + path.sep, '');
const pack = Package.parseFilename(file.path);
if (pack) {
if (!packages[pack.key] || packages[pack.key].versionInt < pack.versionInt) {
packages[pack.key] = {
platform: pack.platform,
type: pack.type,
version: pack.version,
versionInt: pack.versionInt,
path: basepath,
filename: basepath.split(path.sep).pop(),
url: `${publishUrl}/${basepath.replace(path.sep, "/")}`,
}
}
}
cb(null);
})).on('end', function () {
fs.writeFileSync(path.join(publishDir, 'packages.json'), JSON.stringify({
name: name,
version: version,
packages: Object.values(packages),
}, null, 4));
})
}
])(cb);
};
module.exports.Package = Package;