Commit 08fbade8 authored by 熊东起's avatar 熊东起

add:-fish

parents
File added
# Created by .ignore support plugin (hsz.mobi)
.temp
node_modules
dist
/src-js
yarn.lock
package-template.iml
/test/src/bundle.js
/test/src/meta.json
types
# Created by .ignore support plugin (hsz.mobi)
/src/
/test/
*.iml
.temp
/assets
tsconfig.json
{
"name": "@spark/compoundFish",
"version": "1.0.0",
"main": "dist/bundle.js",
"types": "types/index.d.ts",
"license": "MIT",
"scripts": {
"dev": "npm-run-all -p -r dev:**",
"dev:me": "spark package pack -s src -o test/src/bundle.js -w",
"dev:test": "cd test && npm run dev",
"build": "tsc --outDir 'src-js' -t es2017 -d --declarationDir 'types' --jsx preserve && node scripts/copy-others.js 'src-js'",
"pack": "spark package pack -s src -o dist/bundle.js -p",
"declare": "tsc -d --declarationDir 'types' --emitDeclarationOnly",
"spi": "node scripts/mergeSpine",
"pub": "npm run build && read -p 'Input version: ' version && read -p 'Input remark: ' remark && spark package publish -s src -v $version -r $remark"
},
"dependencies": {
"@types/react": "^16.9.56",
"spark-wrapper-fyge": "^1.0.26",
"svga-parser": "^2.0.0"
},
"devDependencies": {
"fs-extra": "^9.0.1",
"less": "^4.1.0",
"npm-run-all": "^4.1.5",
"tslib": "^2.0.1",
"typescript": "^4.1.3"
}
}
# compoundFish
## Install
`yarn add @spark/compoundFish`
## Usage
```js
import {...} from '@spark/compoundFish'
```
## Contribute
1. `yarn dev` to develop package
2. `cd test && yarn && yarn dev` to develop test
## Publish
`npm run pub`
/**
* Created by rockyl on 2021/1/18.
*/
const fs = require('fs-extra')
const path = require('path')
function filter(file) {
let extname = path.extname(file);
return !(extname === '.tsx' || extname === '.ts');
}
fs.copySync('src', process.argv[2], {filter})
const fs = require("fs")
let arg = process.argv.splice(2);
if (!arg[0]) {
console.error("未输入路径");
return
}
var inUrl = arg[0];
var img = fs.readFileSync(inUrl + ".png")
var atlas = fs.readFileSync(inUrl + ".atlas")
var json = fs.readFileSync(inUrl + ".json")
// console.log(img.byteLength)
// console.log(atlas.byteLength)
// console.log(json.byteLength)
//头部信息
var header = new ArrayBuffer(12);
var headerView = new DataView(header);
headerView.setUint32(0, img.byteLength, true);
headerView.setUint32(4, atlas.byteLength, true);
headerView.setUint32(8, json.byteLength, true);
fs.writeFileSync(inUrl + ".spi", Buffer.concat([
toBuffer(header),
img,
atlas,
json
], 12 + img.byteLength + atlas.byteLength + json.byteLength), { encoding: "binary" })
function string2buffer(str) {
// 首先将字符串转为16进制
let val = ""
for (let i = 0; i < str.length; i++) {
if (val === '') {
val = str.charCodeAt(i).toString(16)
} else {
val += ',' + str.charCodeAt(i).toString(16)
}
}
// 将16进制转化为ArrayBuffer
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
}))
}
function bytesToBinary(bytes) {
const length = bytes.length;
let result = '';
for (let i = 0; i < length; i++) {
const binStr = Number(bytes[i]).toString(2)
result += '0'.repeat(8 - binStr.length) + binStr; // 不足八位前置补0
}
return result.toString();
}
function toBuffer(ab) {
// var buf = new Buffer(ab.byteLength);
var buf = Buffer.alloc(ab.byteLength);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
}
function toArrayBuffer(buf) {
var ab = new ArrayBuffer(buf.length);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File added
import * as GAME from "spark-wrapper-fyge";
import GameIndex from "./core/GameIndex";
import { GameMgr } from "./core/GameMgr";
import { loadSpine, loadSpineOnce } from "./core/Loader";
export class GameStage extends GAME.WidgetBase {
private game: GameIndex = null;
private async _setup() {
await loadSpine([
"//yun.duiba.com.cn/aurora/assets/6e7380da60c7b6ea1a2cf4d632c8acd2344bfa61.spi",
"//yun.duiba.com.cn/aurora/assets/b3be7191bda93fd1006dfdb5c0a349765634f026.spi"
]);
// await loadSpineOnce("//yun.duiba.com.cn/aurora/assets/210e9484fce76f282f7bc6f99f985e589062cd46.spi");
const gameIndex = new GameIndex();
this.addChild(gameIndex);
this.game = gameIndex;
const offsetY = document.body.clientWidth / 750 * 1624 - document.body.clientHeight;
gameIndex.position.set(gameIndex.x, gameIndex.y - offsetY);
this.emitEvent('game-ready');
}
onLaunched() {
this._setup();
GameMgr.gameStage = this;
}
/**
* 事件回调
* @param type
* @param payload
*/
onEvent(type: string, payload: any) {
// console.log(type, payload)
switch (type) {
case 'start':
break;
case 'stop':
break;
case "call-fish":
// console.log("召唤鱼--->>>");
this.game && this.game.callOneFish(payload);
break;
case "sort-fish":
this.game && this.game.onSortFish();
break;
case "update-fishery":
this.game && this.game.updateFishery(payload);
break;
case "sell-fish-cb":
this.game && this.game.sellFishCallBack(payload);
break;
case "game-guide":
// console.log("新手引导---->>>>>>step",payload)
this.game && (this.game.guideStep = payload.step);
break;
}
}
/**
* 销毁回调
*/
onDestroy() {
// Tween.removeTweens(this._img);
}
private _showOne = () => {
// const { textArray } = this.props;
// const text = textArray[Math.floor(Math.random() * textArray.length)];
// this._label.text = text;
/**
* 对外派发事件
*/
this.emitEvent('show_one', {})
}
}
/**
* Created by _xdq on 2021/10/09.
* 鱼
*/
import * as GAME from "spark-wrapper-fyge";
import { getSprite, getText } from "./UI";
import { FishType, fishPoolName, FishOptions, FishDir, FishStatus } from "./game.type";
import { GUtils } from './Utils';
import { loadSpineOnce } from "./Loader";
import Event = GAME.Event;
import MouseEvent = GAME.MouseEvent;
import Graphics = GAME.Graphics;
import ObjectPool = GAME.ObjectPool;
import TWEEN = GAME.Tween;
import TEXT_ALIGN = GAME.TEXT_ALIGN;
import Sprite = GAME.Sprite;
import TextField = GAME.TextField;
import Spine = GAME.Spine;
import MovieClip = GAME.MovieClip;
import TextureCache = GAME.TextureCache;
import getAssetByUUID = GAME.getAssetByUUID;
export class Fish extends GAME.Container {
/** 移动方向 - 竖直 */
private _verticalDir: FishDir = FishDir.down;
/** 移动方向 - 水平 */
private _horizontalDir: FishDir = FishDir.left;
/** 移动速度 - 竖直 */
public verticalSpeed: number = 2;
/** 移动速度 - 水平 */
public horizontalSpeed: number = 3;
/** 鱼 */
private fishCon: Sprite = null;
/** 等级 */
private _level: number = 0;
/** 碰撞半径 */
public R: number = 50;
/** 本次是否改变方向 */
public isChangeDir: boolean = false;
/** 等级文字框 */
private levelCon: Graphics = null;
/** 等级文字 */
private levelTxt: TextField = null;
/** 鱼的状态 */
public fishStatus: FishStatus = FishStatus.common;
/** 每秒产生的鱼币 */
private _production: number = 1;
/** 上浮的金币 */
private floatCoin: Graphics = null;
/** 动效 */
private spinePlayer: Spine = null;
/** 打工台编号 */
public workerNum: number = 0;
/** 鱼的id */
public fishId: string = "";
/** 可以合成的动效 */
public compoundAni: MovieClip = null;
/** 鱼的售价 */
public price: number = 0;
/** 鱼的名字 */
public fishName: string = ""
/** 产量文字 */
private proText: TextField = null;
get production(): number {
return this._production;
}
set production(v: number) {
if (this._production == v) return;
this._production = v;
this.updateFloatCoin();
this.proText && (this.proText.text = `+${GUtils.changeUnit(v)}`);
}
public get horizontalDir(): FishDir {
return this._horizontalDir;
}
public set horizontalDir(v: FishDir) {
if(this._horizontalDir == v) return;
this._horizontalDir = v;
if (v === FishDir.right) {
this.scaleX = -1;
this.levelCon.scaleX = -1;
this.floatCoin && (this.floatCoin.scaleX = -1);
} else if (v === FishDir.left) {
this, this.scaleX = 1;
this.levelCon.scaleX = 1;
this.floatCoin && (this.floatCoin.scaleX = 1);
}
}
public get verticalDir(): FishDir {
return this._verticalDir;
}
public set verticalDir(v: FishDir) {
this._verticalDir = v;
}
public get level(): number {
return this._level;
}
public set level(v: number) {
if (this._level == v) return;
this._level = v;
this.levelTxt && (this.levelTxt.text = this._level + '');
this.spinePlayer && (this.spinePlayer.setSkin(this._level + ""));
}
constructor() {
super();
this.initUi();
}
/**初始化ui */
async initUi() {
if (!this.spinePlayer)
await this.loadSpine();
// const fish = getSprite(this, "fish", 0, 0);
// fish.x = -0.5 * fish.width;
// fish.y = -0.2 * fish.height;
// this.fishCon = fish;
// fish.visible = false
// const test = this.addChild(new Graphics());
// test.beginFill(0x000, 0.2);
// test.drawCircle(-10, 10, fish.width / 2 - 30);
// test.endFill();
// this.R = fish.width / 2 - 30;
const levelCon = this.addChild(new Graphics());
levelCon.beginFill(0xff6431, 1);
levelCon.lineStyle(2, 0xffffff, 1, 1)
levelCon.drawCircle(0, 0, 16);
levelCon.endFill();
levelCon.endStroke();
levelCon.position.set(60, 70);
this.levelCon = levelCon;
const leveltxt = getText(levelCon, "0", 20, "0xffffff", TEXT_ALIGN.CENTER, 40, -19, -10.5);
this.levelTxt = leveltxt;
//svga
this.compoundAni = this.addChild(new MovieClip(getAssetByUUID("round-light")));
this.compoundAni.position.set(-112, -70);
this.compoundAni.visible = false;
}
/** 加载鱼动画 */
async loadSpine() {
const spineDataSmall = await loadSpineOnce("//yun.duiba.com.cn/aurora/assets/6e7380da60c7b6ea1a2cf4d632c8acd2344bfa61.spi");
if (this.spinePlayer) return;
const spinePlayer = new Spine(spineDataSmall, false);
this.spinePlayer = spinePlayer;
// console.log(spinePlayer.aniNames);
// console.log(spinePlayer.skinNames);
this.addChild(spinePlayer);
spinePlayer.position.set(0, 60);
spinePlayer.setSkin(this.level + "");
spinePlayer.animationManager.showAni('animation', 0);
// spinePlayer.setSkin("2");
// spinePlayer.animationManager.showAni('qingnian', 0);
}
/** 初始化鱼 */
async reset(data: FishOptions) {
this.level = data.level;
this.fishId = data.fishId;
this.production = data.production || 10;
this.workerNum = data.workerNum;
this.price = data.price;
this.fishName = data.fishName;
if (!this.spinePlayer)
await this.initUi();
if (this.level > 24) {
const spineDataBig = await loadSpineOnce("//yun.duiba.com.cn/aurora/assets/b3be7191bda93fd1006dfdb5c0a349765634f026.spi");
this.removeChild(this.spinePlayer);
const spinePlayer = new Spine(spineDataBig, false);
this.spinePlayer = spinePlayer;
// console.log(spinePlayer.aniNames);
// console.log(spinePlayer.skinNames);
this.addChild(spinePlayer);
spinePlayer.position.set(0, 60);
spinePlayer.animationManager.showAni('qingnian', 0);
}
// this.addChild(this.compoundAni);
this.compoundAni.visible = false;
this.addChild(this.levelCon);
this.spinePlayer.setSkin(this.level + "");
this.position.set(data.position.x, data.position.y);
this.updateFloatCoin();
this.levelTxt.text = this.level + '';
this.verticalSpeed = data.speed.verticalSpeed;
this.horizontalSpeed = data.speed.horizontalSpeed;
this.verticalDir = data.dir.verticalDir;
this.horizontalDir = data.dir.horizontalDir;
}
/** 刷新头顶鱼币 */
private updateFloatCoin() {
if (this.floatCoin) {
TWEEN.removeTweens(this.floatCoin);
this.removeChild(this.floatCoin);
this.floatCoin = null;
}
let l = GUtils.changeUnit(this.production).toString().length;
this.floatCoin = this.addChild(new Graphics());
this.floatCoin.beginFill(0x000, 0.3);
this.floatCoin.drawRoundedRect(0, 0, (l + 1) * 21 + 34, 40, 20);
this.floatCoin.endFill();
let originx = -this.floatCoin.width / 2 - 10, originY = -this.floatCoin.height / 2 - 50;
this.floatCoin.position.set(originx, originY);
this.floatCoin.anchorX = this.floatCoin.width / 2;
this.floatCoin.anchorY = this.floatCoin.height / 2;
const coin = getSprite(this.floatCoin, "fish-coin", 5, 5);
const leveltxt = getText(this.floatCoin, `+${GUtils.changeUnit(this.production)}`, 24, "0xffffff", TEXT_ALIGN.CENTER, (l + 1) * 20, 36, 8);
leveltxt.bold = true;
this.proText = leveltxt;
this.floatCoin.alpha = 0;
if (this.horizontalDir === FishDir.right) {
this.floatCoin && (this.floatCoin.scaleX = -1);
} else if (this.horizontalDir === FishDir.left) {
this.floatCoin && (this.floatCoin.scaleX = 1);
}
TWEEN.get(this, { loop: false })
.wait(GUtils.getRandom(4000, 0))
.call(() => {
this.floatCoin && TWEEN.get(this.floatCoin, { loop: true })
.set({ y: originY, alpha: 1 })
.to({ y: originY - 40, alpha: 0.1 }, 1000)
.set({ y: originY, alpha: 0 })
.wait(4000);
});
}
/** 展示可以合成动画 */
showCanCompoundAni() {
if (this.compoundAni && this.compoundAni.visible) return;
if (this.compoundAni) {
this.addChild(this.compoundAni);
this.compoundAni.visible = true;
} else {
this.compoundAni = this.addChild(new MovieClip(getAssetByUUID("round-light")));
this.compoundAni.position.set(-112, -70);
this.compoundAni.visible = true;
}
}
/** 移除 */
onRecyle() {
try {
this.level = 0;
this.fishId = "";
this.price = 0;
this.fishName = "";
// TWEEN.removeTweens(this);
TWEEN.removeTweens(this.floatCoin);
// TWEEN.removeTweens(this.floatCoin);
this.removeChild(this.floatCoin);
this.floatCoin = null;
this.parent && this.parent.removeChild(this);
GAME.ObjectPool.recycleObject(fishPoolName, this);
// super.destroy();
} catch (error) {
console.log(error)
}
}
}
\ No newline at end of file
/**
* Created by _xdq on 2021/10/09.
* 配置
*/
export default class GameCfg {
/** 鱼的数量 */
static MAX_FISH_COUNT: number = 12;
/** 鱼的最大速度 */
static FISH_MAX_SPEED: number = 0.38;
/** 鱼的最小速度 */
static FISH_MIN_SPEED: number = 0.22;
/** 派发事件 -- 点击解锁 */
static GAME_UN_LOCK: string = "game-unlock";
/** 选中拖动的鱼 */
static SELECTED_FISH: string = "selected-fish";
/** 鱼被拖动 */
static DRAG_FISH: string = "drag-fish";
/** 鼠标抬起松开鱼 */
static LOOSEN_FISH: string = "loosen-fish";
/** 合成小鱼 */
static COMPOUND_FISH: string = "compound-fish";
/** 拖到打工台 */
static GET_WORKER_FISH: string = "get-worker-fish";
/** 从打工台召回小鱼 */
static CALL_FISH_BACK_FISHERY: string = "call-fish-back-fishery";
/** 删除小鱼 */
static DELETE_FISH: string = "delete-fish"
/** 打工台位置 */
static workerSites: { [k: string]: number }[] = [
{
id: 1,
x: 78,
y: 20
},
{
id: 2,
x: 196,
y: 48
},
{
id: 3,
x: 324,
y: 60
},
{
id: 4,
x: 448,
y: 48
},
{
id: 5,
x: 562,
y: 20
}
]
}
\ No newline at end of file
This diff is collapsed.
import { GameStage } from "../GameStage";
export namespace GameMgr {
export let gameStage: GameStage = null;
}
\ No newline at end of file
/**
* Created by _xdq on 2021/05/11.
*/
import * as GAME from "spark-wrapper-fyge";
const cache = {};
/**
* 加载所有的spine
* @export
* @param {(string | string[])} urls
* @param {(loaded: number, total: number) => void} [onProcess]
* @param {() => void} [onComplete]
* @return {*} {Promise<any>}
*/
export const loadSpine = async (urls: string | string[], onProcess?: (loaded: number, total: number) => void, onComplete?: () => void): Promise<any> => {
try {
let results = [];
if (typeof urls === 'string') {
results.push(await loadSpineOnce(urls).then(res => {
try {
onProcess && onProcess(1, 1);
onComplete && onComplete();
} catch (error) {
console.warn(error);
}
return res;
}));
} else {
let total = urls.length, loadedCount = 0;
for (let item of urls) {
results.push(await loadSpineOnce(item).then(res => {
try {
loadedCount++;
onProcess && onProcess(loadedCount, total);
if (loadedCount >= total) {
onComplete && onComplete();
}
} catch (error) {
console.warn(error);
}
return res;
}));
}
}
return results;
} catch (e) {
console.warn(e);
}
}
/**
* 加载一个spine数据
* @export
* @param {string} url
* @return {*}
*/
export const loadSpineOnce = async (url: string) => {
let spineData = cache[url];
if (!spineData) {
spineData = await loadSpineData(url);
cache[url] = spineData;
}
// console.log("0000",spineData)
return spineData;
}
/**
* 加载spine FYGE.loadSpine
* @param {string} url
*/
const loadSpineData = async (url: string) => {
return await new Promise((resolve, reject) => {
try {
GAME.loadSpine(url, (spineData: any) => {
resolve(spineData);
console.log("9889",spineData)
});
} catch (error) {
reject(error);
}
});
}
/**
* Created by _xdq on 2021/10/09.
* UI
*/
import * as GAME from "spark-wrapper-fyge";
/**
* 获取图片
* @param uuid
* @param _x
* @param _y
*/
export const getSprite = function (parent: GAME.Container, uuid: string, _x: number = 0, _y: number = 0, _anchorX: number = 0, _anchorY: number = 0): GAME.Sprite {
let _sprite = new GAME.Sprite(GAME.TextureCache[uuid]);
_sprite.x = _x;
_sprite.y = _y;
_sprite.anchorX = _anchorX * _sprite.width;
_sprite.anchorY = _anchorY * _sprite.height;
_sprite.position.set(_x, _y);
parent && parent.addChild(_sprite);
return _sprite;
}
/**
* 获取文字
* @param parent
* @param txt
* @param size
* @param color
* @param align
* @param textWidth
* @param x
* @param y
* @returns
*/
export const getText = function (
parent: GAME.Container,
txt: string,
size: number,
color: string = "#000000",
align: GAME.TEXT_ALIGN = GAME.TEXT_ALIGN.LEFT,
textWidth: number = 0,
x: number = 0,
y: number = 0
): GAME.TextField {
const text = new GAME.TextField();
text.fillColor = color;
text.size = size;
text.textWidth = textWidth;
text.textAlign = align;
text.position.set(x, y);
text.text = txt;
parent && parent.addChild(text);
return text;
}
/**
* 获取合成动效
* @param parent
*/
export const getCompounCompletedAni = function (parent: GAME.Container, position: { [k: string]: number }): GAME.MovieClip {
const compoundAni = parent.addChild(new GAME.MovieClip(GAME.getAssetByUUID("compound-ani")));
compoundAni.position.set(position.x - 217, position.y - 217);
compoundAni.visible = true;
compoundAni.startAniRange(1, compoundAni.totalFrames, 1, () => {
compoundAni.visible = false;
parent && parent.removeChild(compoundAni);
});
return compoundAni;
}
/** 横着的引导 */
export const getGuideAni = function (parent: GAME.Container, step: number, position: { [k: string]: number }): GAME.Container {
let con = parent.addChild(new GAME.Container());
let _str = "";
if (step == 3 || step == 7) {
_str = "guide-1-ani";
} else if (step == 8) {
_str = "guide-2-ani";
}
// console.log("99999===", _str);
if (step == 7) {
const tip = getSprite(con, "ver-bubble");
tip.position.set(position.x - 50, position.y - 200);
}
if(step == 8){
const tip = getSprite(con, "hor-bubble");
tip.position.set(position.x - 200, position.y - 220);
}
const guideAni = con.addChild(new GAME.MovieClip(GAME.getAssetByUUID(_str)));
guideAni.position.set(position.x - 50, position.y - 50);
guideAni.visible = true;
guideAni.mouseChildren = false;
guideAni.mouseEnable = false;
con.mouseChildren = false;
con.mouseEnable = false;
return con;
}
/**
* Created by _xdq on 2021/04/07.
* 公共方法
* @export
* @class GUtils
*/
export class GUtils {
/** 随机数 */
static getRandom(max: number, min: number): number {
return Number((Math.random() * (max - min) + min).toFixed(2));
}
/** 获取角度 */
static getAngle(dy: number, dx: number): number {
const angle = Math.atan2(dy, dx) / Math.PI * 180;
return angle;
}
/** 判断整数 */
static isInteger(obj: any) {
return typeof obj === 'number' && obj % 1 === 0;
}
/** 单位转换 */
static changeUnit(amount: number): string {
if (amount >= 10 ** 12) {
if (amount % 10 ** 12 < 10 ** 10)
return (amount / 10 ** 12).toFixed(0) + "兆"
else
return (amount / 10 ** 12).toFixed(2) + "兆"
}
if (amount >= 10 ** 8) {
if (amount % 10 ** 8 < 10 ** 6)
return (amount / 10 ** 8).toFixed(0) + "亿"
else
return (amount / 10 ** 8).toFixed(2) + "亿"
}
if (amount >= 10000) {
if (amount % 10000 < 100)
return (amount / 10000).toFixed(0) + "万"
else
return (amount / 10000).toFixed(2) + "万"
}
return amount + "";
}
}
\ No newline at end of file
/**
* Created by _xdq on 2021/10/09.
* 打工位
*/
import * as GAME from "spark-wrapper-fyge";
import { Fish } from "./Fish";
import { WorkerStatus } from "./game.type";
import GameCfg from "./GameCfg";
import { GameMgr } from "./GameMgr";
import { loadSpineOnce } from "./Loader";
import { getSprite, getText } from "./UI";
import { GUtils } from './Utils';
import Container = GAME.Container;
import Sprite = GAME.Sprite;
import Graphics = GAME.Graphics;
import MouseEvent = GAME.MouseEvent;
import Spine = GAME.Spine;
import TEXT_ALIGN = GAME.TEXT_ALIGN;
import TWEEN = GAME.Tween;
import TextField = GAME.TextField;
export default class WorkeSite extends Container {
/** 工作台id */
public id: number = 0;
/** 打工UI */
private workerStatusUI: { [k: string]: Container | Sprite } = {};
/** 打工状态 */
private _workerStatus: WorkerStatus = WorkerStatus.lock;
/** 碰撞半径 */
public R: number = 50;
/** 碰撞偏移量 */
public colliderOffset: { [k: string]: number } = { x: 54, y: 50 };
/** 正在打工的鱼 */
private _workingFish: Fish = null;
/** 召回鱼 */
public callBackFish: (p: this) => void = () => { };
/** 上浮的金币 */
private floatCoin: Graphics = null;
/** 上浮文字 */
private floatText: TextField = null;
public get workerStatus(): WorkerStatus {
return this._workerStatus;
}
public set workerStatus(v: WorkerStatus) {
this._workerStatus = v;
for (let item in this.workerStatusUI) {
this.workerStatusUI[item].visible = false;
}
this.workerStatusUI[v].visible = true;
}
constructor() {
super();
//未解锁
const lock = getSprite(this, "lock-worker", 0, 0);
lock.mouseEnable = true;
lock.mouseChildren = true;
lock.addEventListener(MouseEvent.CLICK, () => {
GameMgr.gameStage.emitEvent(GameCfg.GAME_UN_LOCK, {
id: this.id
})
}, this);
//已解锁
const alreadyLocked = getSprite(this, "already-lock-worker", -4, -36);
alreadyLocked.mouseChildren = true;
alreadyLocked.mouseEnable = true;
//正在打工
const working = this.addChild(new Container());
const bg = working.addChild(new Graphics());
bg.beginFill(0x000000, 0.2);
bg.drawEllipse(0, 0, 55, 26);
bg.endFill();
bg.position.set(54, 58);
this.initWorkFish(working);
this.workerStatusUI['lock'] = lock;
this.workerStatusUI['alreadyKLocked'] = alreadyLocked;
this.workerStatusUI['working'] = working;
this.workerStatus = WorkerStatus.lock;
}
//打工鱼
async initWorkFish(parent: Container) {
const spineData = await loadSpineOnce("//yun.duiba.com.cn/aurora/assets/b3be7191bda93fd1006dfdb5c0a349765634f026.spi");
const spinePlayer = new Spine(spineData, false);
// console.log(spinePlayer.aniNames);
// console.log(spinePlayer.skinNames);
parent.addChild(spinePlayer);
spinePlayer.position.set(50, 100);
spinePlayer.setSkin("default");
spinePlayer.animationManager.showAni('dagong', 0);
const callBackBtn = getSprite(parent, "call-back-btn", 10, 65);
callBackBtn.mouseEnable = true;
callBackBtn.mouseChildren = true;
callBackBtn.addEventListener(MouseEvent.CLICK, () => {
this.callBackFish && this.callBackFish(this);
}, this);
}
set workingFish(v: Fish) {
if (this._workingFish == v) return;
this._workingFish = v;
//飘金币
if (this.floatCoin) {
TWEEN.removeTweens(this.floatCoin);
this.removeChild(this.floatCoin);
this.floatCoin = null;
}
if (this.workingFish && !this.floatCoin) {
// console.log("0000",this.workingFish.production)
let l = GUtils.changeUnit(this.workingFish.production).toString().length;
this.floatCoin = this.addChild(new Graphics());
this.floatCoin.beginFill(0x000, 0.3);
this.floatCoin.drawRoundedRect(0, 0, (l + 1) * 21 + 34, 40, 20);
this.floatCoin.endFill();
let originx = 5, originY = -this.floatCoin.height / 2 - 30;
this.floatCoin.position.set(originx, originY);
this.floatCoin.anchorX = this.floatCoin.width / 2;
this.floatCoin.anchorY = this.floatCoin.height / 2;
const coin = getSprite(this.floatCoin, "fish-coin", 5, 5);
const leveltxt = getText(this.floatCoin, `+${GUtils.changeUnit(this.workingFish.production)}`, 24, "0xffffff", TEXT_ALIGN.CENTER, (l + 1) * 20, 36, 10);
leveltxt.bold = true;
this.floatText = leveltxt;
this.floatCoin.alpha = 0;
TWEEN.get(this, { loop: false })
.wait(GUtils.getRandom(4000, 0))
.call(() => {
this.floatCoin && TWEEN.get(this.floatCoin, { loop: true })
.set({ y: originY, alpha: 1 })
.to({ y: originY - 20, alpha: 0.1 }, 800)
.set({ y: originY, alpha: 0 })
.wait(4000);
});
}
}
get workingFish(): Fish {
return this._workingFish;
}
//初始化
reset() {
}
}
\ No newline at end of file
/**
* Created by _xdq on 2021/10/09.
* 类型
*/
export type FishType = { [key: string]: number };
export type CommonType = { [key: string]: number };
/** 对象池 */
export const fishPoolName = "fish-pool";
/** 鱼的方向 */
export enum FishDir {
up = "up",
down = "down",
left = "left",
right = "right"
}
/**
* 鱼配置
*/
export interface FishOptions {
fishId: string,
level: number,
workerNum: number,
position: CommonType,
speed: CommonType,
dir: { [key: string]: FishDir }
production: number,
price: number,
fishName: string
}
/** 打工状态 */
export enum WorkerStatus {
lock = "lock",
alreadyKLocked = "alreadyKLocked",
working = "working"
}
/** 鱼的状态 */
export enum FishStatus {
working = 1,
common = 2,
summon = 3,//召唤
sell = 4,//售卖
drag = 5,//拖动的鱼
guide = 6//引导鱼
}
\ No newline at end of file
declare function getMetaConfig(id: string);
declare const PROCESS = 1;
declare const DOM_COMPONENT = 2;
declare const CANVAS_WIDGET = 3;
import { GameStage } from "./GameStage";
import { registerCustomLoader } from 'spark-wrapper-fyge'
import { svgaLoader } from 'svga-parser'
/**
* CompoundFish模块
* @description CompoundFish模块的工厂方法
* @ctype CANVAS_WIDGET
*/
registerCustomLoader('.svga', svgaLoader);
export function CompoundFish() {
return new GameStage(getMetaConfig('CompoundFish'));
}
{
"id": "CompoundFish",
"name": "测试模块",
"desc": "实现了测试模块",
"config": {
"CompoundFish": {
"props": [{
"name": "textArray",
"alias": "文本组",
"type": "string",
"default": ["aaa", "bbb", "ccc", "ddd"]
}],
"assets": [{
"name": "打工台",
"url": "//yun.duiba.com.cn/aurora/assets/ae8dd620c14d546627da7ef77a76cd5902b6bc5a.png",
"uuid": "work-stage",
"ext": ".png"
},
{
"name": "鱼",
"url": "//yun.duiba.com.cn/aurora/assets/84ad176bb723cb1f74830a35b6a91e8a41aa5c82.png",
"uuid": "fish",
"ext": ".png"
},
{
"name": "背景",
"url": "//yun.duiba.com.cn/aurora/assets/551bcd0b9858e918461f2e64d97a1af0ac0c57f3.jpg",
"uuid": "bg",
"ext": ".jpg"
},
{
"name": "未解锁",
"url": "//yun.duiba.com.cn/aurora/assets/fea6f82cb5aa55b992989f803faebd57105f41b6.png",
"uuid": "lock-worker",
"ext": ".png"
},
{
"name": "已解锁",
"url": "//yun.duiba.com.cn/aurora/assets/521891c4dfb0d1bb84154ec888b5823083523000.png",
"uuid": "already-lock-worker",
"ext": ".png"
},
{
"name": "召回",
"url": "//yun.duiba.com.cn/aurora/assets/8cb29929555c4c35029a8208ce1a66c52a1f9fc2.png",
"uuid": "call-back-btn",
"ext": ".png"
},
{
"name": "鱼示意",
"url": "//yun.duiba.com.cn/aurora/assets/5d0a8eb857cedb7035e38936a5527df5ae7ad405.png",
"uuid": "show-worker-fish",
"ext": ".png"
},
{
"name": "鱼币",
"url": "//yun.duiba.com.cn/aurora/assets/9b67b68c62f1cb76c8631b51a52568dc466aa02e.png",
"uuid": "fish-coin",
"ext": ".png"
},
{
"name": "幼年鱼动效",
"url": "//yun.duiba.com.cn/aurora/assets/210e9484fce76f282f7bc6f99f985e589062cd46.spi",
"uuid": "small-fish-spine",
"ext": ".spi"
},
{
"name": "光环",
"url": "//yun.duiba.com.cn/aurora/assets/1190bc60070a177e3c869e897cc23bde71291170.svga",
"uuid": "round-light",
"ext": ".svga"
},
{
"name": "合成动效",
"url": "//yun.duiba.com.cn/aurora/assets/3e2bf900f89c4cd8f8e6627466fa5f41ba04e66f.svga",
"uuid": "compound-ani",
"ext": ".svga"
},
{
"name": "横向手势 ",
"url": "//yun.duiba.com.cn/aurora/assets/6c035cdff9c92ecccc4195db284af09a4b81d9b3.svga",
"uuid": "guide-1-ani",
"ext": ".svga"
},
{
"name": "竖着手势",
"url": "//yun.duiba.com.cn/aurora/assets/4f9198a01a75b7454533df164fe0744996c3be6f.svga",
"uuid": "guide-2-ani",
"ext": ".svga"
},
{
"name": "气泡1",
"url": "//yun.duiba.com.cn/aurora/assets/a6f987f680a2bbced5b578cf6a7183d70475d33b.png",
"uuid": "ver-bubble",
"ext": ".png"
},
{
"name": "气泡2",
"url": "//yun.duiba.com.cn/aurora/assets/ca1bd3974d6bd58f9af2a17278e3af0042f340bb.png",
"uuid": "hor-bubble",
"ext": ".png"
}
],
"events": {
"in": {
"start": {
"alias": "开始"
},
"stop": {
"alias": "停止"
}
},
"out": {
"show_one": {
"alias": "展示一个文本",
"data": {
"text": "文本"
}
}
}
}
}
}
}
\ No newline at end of file
File added
EXTEND_ESLINT = true
/**
* Created by rockyl on 2020/11/20.
*/
const path = require('path');
module.exports = {
devServer: function(configFunction){
return function(proxy, allowedHost) {
const config = configFunction(proxy, allowedHost);
config.contentBase = [path.resolve('public'), path.resolve('../')];
return config;
};
}
}
{
"name": "test",
"version": "0.1.0",
"private": true,
"dependencies": {
"@spark/ui": "^2.0.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.3",
"svga-parser": "^2.0.0"
},
"scripts": {
"dev": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-scripts ",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"react-app-rewired": "^2.1.6",
"sass": "^1.29.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>test: compoundFish</title>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.0/rem.min.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
<!-- <script src="https://yun.duiba.com.cn/db_games/libs0126/stats.js"></script> -->
</html>
import React, { useState, useRef } from 'react';
import './App.scss';
import { CanvasWidget } from '@spark/ui';
import { CompoundFish } from "./bundle";
/**
* 配置覆盖
*/
const widgetConfig = {
props: {
},
assets: [
{
"name": "红包",
"url": "//yun.duiba.com.cn/aurora/df6e289d635a6a2b4f3df055e00301f63b07d863.png",
"uuid": "image",
"ext": ".png"
},
],
}
function App() {
const [widgetVisible, setWidgetVisible] = useState(true);
const widgetRef = useRef();
function onReady(widget) {
console.log('CanvasWidget ready!')
}
/**
* 事件回调
*/
function onEvent(type, payload) {
// console.log(type, payload);
if (type === "game-ready") {
widgetRef.current.emitEvent("update-fishery", {
fishData: [
{
fishId: "1002",
id: 2,
level: 2,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1004",
id: 2,
level: 1,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1005",
id: 3,
level: 3,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1006",
id: 2,
level: 8,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1007",
id: 2,
level: 6,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1008",
id: 3,
level: 5,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1009",
id: 2,
level: 2,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "10010",
id: 2,
level: 1,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "10011",
id: 3,
level: 41,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "10012",
id: 2,
level: 21,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "10013",
id: 2,
level: 1,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "10014",
id: 3,
level: 34,
speed: 0,
userId: 999,
efficiency: 10
}
],
workerSiteData: [
{
id: 1,
status: 1,
fishId: 1
},
{
id: 2,
status: 2,
fishId: 1
},
{
id: 3,
status: 0,
fishId: 1
},
{
id: 4,
status: 0,
fishId: 1
},
{
id: 5,
status: 0,
fishId: 1
}
],
guideStep: -1
});
}
}
function onAssetsProcess(loaded, total) {
console.log(`assets load process:${loaded}/${total}`)
}
function onAssetsComplete() {
console.log(`assets load complete`);
}
function onClickButton(type) {
switch (type) {
case 'setup':
setWidgetVisible(true);
break;
case 'unSetup':
setWidgetVisible(false);
break;
default:
widgetRef.current.emitEvent(type)
break;
}
}
function onUpdate() {
widgetRef.current.emitEvent("update-fishery", {
fishData: [
{
fishId: "1002",
id: 2,
level: 2,
speed: 0,
userId: 999,
efficiency: 10
},
{
fishId: "1004",
id: 2,
level: 2,
speed: 0,
userId: 999,
efficiency: 10
}
],
workerSiteData: [
{
id: 1,
status: 1,
fishId: 1
},
{
id: 2,
status: 2,
fishId: 1
},
{
id: 3,
status: 0,
fishId: 1
},
{
id: 4,
status: 0,
fishId: 1
},
{
id: 5,
status: 0,
fishId: 1
}
],
guideStep: 8
});
}
function onSellFish() {
widgetRef.current.emitEvent("sell-fish-cb", false)
}
return (
<div className="App">
<div className="control-bar">
{/* <button onClick={e => onClickButton('setup')}>setup</button>
<button onClick={e => onClickButton('unSetup')}>unSetup</button> */}
<button onClick={e => onClickButton('start')}>start</button>
<button onClick={e => onClickButton('stop')}>stop</button>
<button onClick={e => onClickButton('call-fish')}>召唤鱼</button>
<button onClick={e => onClickButton('sort-fish')}>鱼排序</button>
<button onClick={e => onUpdate()}>鱼更新</button>
<button onClick={e => onSellFish()}>鱼售卖</button>
</div>
{
widgetVisible ? <CanvasWidget ref={widgetRef} className="canvas-widget" widgetFactory={CompoundFish} widgetConfig={widgetConfig}
onEvent={onEvent}
renderMode="webgl"
onReady={onReady} onAssetsProcess={onAssetsProcess}
onAssetsComplete={onAssetsComplete} /> : null
}
</div>
);
}
export default App;
.App {
position: fixed;
width: 100%;
height: 100%;
label{
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.canvas-widget {
width: 100%;
height: 100%;
}
.control-bar {
position: absolute;
right: 10px;
bottom: 10px;
}
}
import React from 'react';
import { render } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
import React from 'react';
import ReactDOM from 'react-dom';
import './index.scss';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
html, body, #root{
width: 100%;
height: 100%;
}
body {
margin: 0;
font-size: 14px;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';
{
"compilerOptions": {
"module": "ES6",
"target": "ES5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"lib": [
"ES2015",
"DOM"
]
},
"include": ["src"]
}
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