Merge pull request 'Close #13: add chip-handler template' (#22) from feature/add-chip-handler-template into develop

Reviewed-on: dev-tech/ts-table-game-template#22
Reviewed-by: Le Hoang Nam <nam.le@noreply.localhost>
This commit is contained in:
Le Hoang Nam 2025-06-16 12:50:05 +08:00
commit b0c52fcc50
12 changed files with 470 additions and 20 deletions

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "d399318b-de18-4aff-ae04-5f7c731b90ad",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "62713683-a0e9-464a-8fd9-52d3481284ff",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,118 @@
[
{
"__type__": "cc.Prefab",
"_name": "",
"_objFlags": 0,
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"asyncLoadAssets": false,
"readonly": false
},
{
"__type__": "cc.Node",
"_name": "chip-handler",
"_objFlags": 0,
"_parent": null,
"_children": [],
"_active": true,
"_components": [
{
"__id__": 2
},
{
"__id__": 3
}
],
"_prefab": {
"__id__": 4
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 0,
"height": 0
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
108.59,
440.534,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "a2ae94dyIFJwqWb6gKNDdcK",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"chipPrefab": {
"__uuid__": "bf77bfc7-abcc-4d29-8ab3-05ec46df58eb"
},
"animChip": {
"__id__": 3
},
"_id": ""
},
{
"__type__": "feac7ZD+8ZN64Md38yUI14H",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"winNode": null,
"collectNode": null,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "",
"sync": false
}
]

View File

@ -0,0 +1,9 @@
{
"ver": "1.3.2",
"uuid": "880f2aa7-1582-4df0-9937-53afb2f7e631",
"importer": "prefab",
"optimizationPolicy": "AUTO",
"asyncLoadAssets": false,
"readonly": false,
"subMetas": {}
}

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "559a140f-5d7f-43ad-a4d5-8c122c87ca2c",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,89 @@
import gsap from "gsap";
import getDecorators from "inversify-inject-decorators";
import { Chip } from "../../chip/scripts/chip";
import { container } from "../../plugins/core";
const { ccclass, property } = cc._decorator;
const { lazyInject } = getDecorators(container, false);
@ccclass
export class ChipHandlerAnim extends cc.Component
{
@property(cc.Node)
private winNode: cc.Node = null;
@property(cc.Node)
private collectNode: cc.Node = null;
public hide(nodeTween: cc.Node): void
{
gsap.to(nodeTween, {
duration: 0.2,
opacity: 0,
onComplete: () =>
{
nodeTween.active = false;
}
});
}
public place(nodeTween: cc.Node): void
{
nodeTween.setPosition(this.getRandomRadianPosition(cc.Vec2.ZERO));
var currentPos = nodeTween.position;
var newPos = new cc.Vec2(currentPos.x, currentPos.y);
newPos.y += 40;
nodeTween.setPosition(newPos);
gsap.to(nodeTween, {
duration: 0.2,
x: currentPos.x,
y: currentPos.y,
});
}
public collect(chip: Chip, isDelayRandomTime: boolean): void
{
var startPos = chip.node.parent.convertToNodeSpaceAR(chip.node.convertToWorldSpaceAR(cc.Vec2.ZERO));
var endPos = chip.node.parent.convertToNodeSpaceAR(this.collectNode.convertToWorldSpaceAR(cc.Vec2.ZERO));
this.move(chip.node, startPos, this.getRandomRadianPosition(endPos), true, isDelayRandomTime);
}
public win(nodeTween: cc.Node): void
{
var startPos = nodeTween.parent.convertToNodeSpaceAR(this.winNode.convertToWorldSpaceAR(cc.Vec2.ZERO));
var endPos = nodeTween.parent.convertToNodeSpaceAR(this.node.convertToWorldSpaceAR(cc.Vec2.ZERO));
this.move(nodeTween, this.getRandomRadianPosition(startPos), this.getRandomRadianPosition(endPos), false, true);
}
private move(nodeTween: cc.Node, startPos: cc.Vec2, endPos: cc.Vec2, isHideOnComplete: Boolean = false, isRandomTime: Boolean = false)
{
nodeTween.setPosition(startPos);
var timeRandom = isRandomTime ? Math.random() * 1.5 : 0;
timeRandom += 0.5;
const timeline = gsap.timeline();
nodeTween.setPosition(startPos);
timeline.to(nodeTween, {
duration: timeRandom,
x: endPos.x,
y: endPos.y,
});
if (isHideOnComplete == true)
{
timeline.add(() =>
{
this.hide(nodeTween);
});
}
}
private getRandomRadianPosition(pos: cc.Vec2): cc.Vec2
{
var randomRadianPos = cc.v2(pos.x, pos.y);
randomRadianPos.x += Math.random() * 50 - 25;
randomRadianPos.y += Math.random() * 50 - 25;
return randomRadianPos;
}
}

View File

@ -0,0 +1,10 @@
{
"ver": "1.1.0",
"uuid": "feac7643-fbc6-4deb-831d-dfcc94235e07",
"importer": "typescript",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,75 @@
import getDecorators from "inversify-inject-decorators";
import { ChipColorConfig } from "../../chip/config/chip-color-config";
import { Chip } from "../../chip/scripts/chip";
import { container } from "../../plugins/core";
const { ccclass, property } = cc._decorator;
const { lazyInject } = getDecorators(container, false);
@ccclass
export class ChipHandlerCalculator
{
public static getChipsToCollectByValue(value: number, listChips: Chip[]): Chip[]
{
var result: Chip[] = [];
var sumRemove = 0;
for (var index = listChips.length - 1; index >= 0; index--)
{
var chip = listChips[index];
if (sumRemove < value)
{
sumRemove += chip.getChipValue();
result.push(chip);
listChips.splice(index, 1);
} else
{
break;
}
}
return result;
}
public static getChipValuesToSpawn(value: number, listBetOption: number[]): number[]
{
var result: number[] = [];
var sum = 0;
var oddNumber = value;
var maxChipValue = listBetOption[listBetOption.length - 1];
var maxChipIndex = this.getMaxChipIndexByChipValue(maxChipValue);
var listChipValue = ChipColorConfig.getListChipValue();
while (sum < value && oddNumber >= listChipValue[0])
{
for (var index = maxChipIndex; index >= 0; index--)
{
var chipValue = listChipValue[index];
if (sum + chipValue <= value)
{
sum += chipValue;
result.push(chipValue);
break;
}
}
oddNumber = value - sum;
}
return result;
}
private static getMaxChipIndexByChipValue(maxPoint: number): number
{
var maxIndex = 0;
var listChipValue = ChipColorConfig.getListChipValue();
for (var index = 0; index < listChipValue.length; index++)
{
var point = listChipValue[index];
if (point > maxPoint)
{
break;
}
maxIndex = index;
}
return maxIndex;
}
}

View File

@ -0,0 +1,10 @@
{
"ver": "1.1.0",
"uuid": "32e6a5e1-debf-4cd3-ade5-a82a9a75b1b3",
"importer": "typescript",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,110 @@
import getDecorators from "inversify-inject-decorators";
import { Chip } from "../../chip/scripts/chip";
import { container, ListBetOptionModel, MODEL } from "../../plugins/core";
import { ChipHandlerAnim } from "./chip-handler-anim";
import { ChipHandlerCalculator } from "./chip-handler-calculator";
const { ccclass, property } = cc._decorator;
const { lazyInject } = getDecorators(container, false);
@ccclass
export class ChipHandler extends cc.Component
{
@lazyInject(MODEL.ListBetOption)
private listBetOptionModel: ListBetOptionModel;
@property(cc.Prefab)
private chipPrefab: cc.Prefab = null;
@property(ChipHandlerAnim)
private animChip: ChipHandlerAnim = null;
private listChips: Chip[] = [];
private totalChipValue: number = 0;
public updateChipBetValue(newValue: number): void
{
if (this.totalChipValue == newValue) return;
if (this.totalChipValue > 0 && newValue == 0)
{
this.collectAll();
return;
}
if (newValue > this.totalChipValue)
{
this.addBet(newValue - this.totalChipValue);
}
else if (newValue < this.totalChipValue)
{
this.collect(this.totalChipValue - newValue);
}
this.totalChipValue = newValue;
}
public hideAll(): void
{
if (!this.listChips) return;
this.listChips.forEach(chip =>
{
this.animChip.hide(chip.node);
});
this.listChips = [];
this.totalChipValue = 0;
}
private collectAll(): void
{
this.listChips.forEach(chip =>
{
this.animChip.collect(chip, true);
});
this.listChips = [];
this.totalChipValue = 0;
}
private collect(value: number)
{
var arrayChipReturn = ChipHandlerCalculator.getChipsToCollectByValue(value, this.listChips);
arrayChipReturn.forEach(chip =>
{
this.animChip.collect(chip, false);
});
}
private addWin(totalWinPoint: number): void
{
if (totalWinPoint <= 0) return;
if (totalWinPoint < this.totalChipValue) return;
var chipValue = totalWinPoint - this.totalChipValue;
this.totalChipValue = totalWinPoint;
var listChipValue = ChipHandlerCalculator.getChipValuesToSpawn(chipValue, this.listBetOptionModel.listBetOption);
listChipValue.forEach(chipValue =>
{
var chip = this.spawn();
chip.setChipValue(chipValue);
this.animChip.win(chip.node);
});
}
private addBet(value: number): void
{
var arrayChipValue = ChipHandlerCalculator.getChipValuesToSpawn(value, this.listBetOptionModel.listBetOption);
arrayChipValue.forEach(chipValue =>
{
var chip = this.spawn();
chip.setChipValue(chipValue);
this.animChip.place(chip.node);
});
}
private spawn(): Chip
{
var chip = cc.instantiate(this.chipPrefab).getComponent(Chip);
chip.node.active = true;
this.listChips.push(chip);
this.node.addChild(chip.node);
chip.node.setPosition(cc.v2(0, 0));
return chip;
}
}

View File

@ -0,0 +1,10 @@
{
"ver": "1.1.0",
"uuid": "a2ae9e1d-c881-49c2-a59b-ea028d0dd70a",
"importer": "typescript",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -1,4 +1,3 @@
import gsap from "gsap";
import { ChipColorConfig } from "../config/chip-color-config";
const { ccclass, property } = cc._decorator;
@ -24,23 +23,4 @@ export class Chip extends cc.Component
{
return this.value;
}
public placeChip(value: number): void
{
this.setChipValue(value);
var currentPos = this.node.position;
var newPos = new cc.Vec2(currentPos.x, currentPos.y);
newPos.y += 40;
this.node.setPosition(newPos);
gsap.to(this.node, {
duration: 0.2,
x: currentPos.x,
y: currentPos.y,
});
}
public hideChip(): void
{
this.node.active = false;
}
}