Compare commits
76 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8647c1a859 | ||
|
a41c68fb13 | ||
|
c5b26d716e | ||
|
1e0959c4cf | ||
|
3e54670a1b | ||
|
b41b86bbd3 | ||
|
db2bc0e3cd | ||
|
eedcf5c4dc | ||
|
c171ebc211 | ||
|
5a463239bb | ||
|
5c06cfdbac | ||
|
7985a242fd | ||
|
bef1df48aa | ||
|
8d989d543a | ||
|
849ce34fe5 | ||
|
195a400dc2 | ||
|
66dfcaa0f5 | ||
|
9917a62526 | ||
|
62e50f8b6c | ||
|
dc66be1599 | ||
|
858eba5243 | ||
|
d113cffc7d | ||
|
6af9a14be5 | ||
|
e3fe773634 | ||
|
17cac19c62 | ||
|
26bdd41285 | ||
|
6bf70463fa | ||
|
e3d844abad | ||
|
0373665382 | ||
|
3b0db64792 | ||
|
dd8b731ade | ||
|
c4489e0912 | ||
|
348c889e14 | ||
|
c6473db561 | ||
|
e165d49cb1 | ||
|
26370dce61 | ||
|
f3a12b2aa9 | ||
|
1f5802ee14 | ||
|
080a384ade | ||
|
9469b27348 | ||
|
ca5ba83b07 | ||
|
b1f0cf2c57 | ||
|
1b43e6d760 | ||
|
e0fb21f3fb | ||
|
9bce561441 | ||
|
52be2a6a79 | ||
|
fa491b357d | ||
|
695eacaabc | ||
|
0324b584a5 | ||
|
70e552f5f0 | ||
|
c58e690a47 | ||
|
1593965950 | ||
|
2a1105efa4 | ||
|
04de4666d5 | ||
|
2290c57c1c | ||
|
24d5ad9dc8 | ||
|
fdc296531a | ||
|
becc56f672 | ||
|
58c18ab7ae | ||
|
024d527f3d | ||
|
9b29edaaa1 | ||
|
360f2fc22b | ||
|
2dbc529978 | ||
|
d21f59cafa | ||
|
335fef66ef | ||
|
52480ab29f | ||
|
971f6461ab | ||
|
061aa449c9 | ||
|
78dd9ecd85 | ||
|
d4226137b6 | ||
|
e432026fec | ||
|
3e7718ed04 | ||
|
b78dd54431 | ||
|
22fb72afbc | ||
|
7b9172c27b | ||
|
7e12853a73 |
@@ -1,3 +1,7 @@
|
||||
# What to be concerned for internet syncing
|
||||
1. Server received too late (solution: force confirmation)
|
||||
2. Client received too late (solution: prediction and frame chasing, big impact on user experience because the graphics will be inconsistent if mismatches occur too often)
|
||||
|
||||
# Potential avalanche from local lag
|
||||
Under the current "input delay" algorithm, the lag of a single player would cause all the other players to receive outdated commands, e.g. when at a certain moment
|
||||
- player#1: renderFrameId = 100, significantly lagged due to local CPU overheated
|
||||
@@ -7,9 +11,9 @@ Under the current "input delay" algorithm, the lag of a single player would caus
|
||||
|
||||
players #2, #3 #4 would receive "outdated(in their subjective feelings) but all-confirmed commands" from then on, thus forced to rollback and chase many frames - the lag due to "large range of frame-chasing" would then further deteriorate the situation - like an avalanche.
|
||||
|
||||
In a "no-server & p2p" setup, I couldn't think of a proper way to cope with such edge case. Solely on the frontend we could only mitigate the impact to players #2, #3, #4, e.g. a potential lag due to "large range of frame-chasing" is proactively avoided in `<proj-root>/frontend/assets/scripts/Map.js, function update(dt)`.
|
||||
In a "no-server & p2p" setup, I couldn't think of a proper way to cope with such edge case. Solely on the frontend we could only mitigate the impact to players #2, #3, #4, e.g. a potential lag due to "large range of frame-chasing" is proactively avoided in `<proj-root>/frontend/assets/scripts/Map.js, function update(dt)`.
|
||||
|
||||
However in a "server as authority" setup, the server could force confirming an inputFrame without player#1's upsync, and notify player#1 to apply a "roomDownsyncFrame" as well as drop all its outdated local inputFrames.
|
||||
To be fair, **a "p2p" setup can reduce round-trip to single-trip**, but w/o a point of authority in such case player#1 needs a way to recognize the slowness (e.g. check the received peer inputs) and ticks faster for a while to catch up; in contrast in a "server as authority" setup, the server could force confirming an inputFrame without player#1's upsync, and notify player#1 to apply a "roomDownsyncFrame" as well as drop all its outdated local inputFrames.
|
||||
|
||||
# Start up frames
|
||||
renderFrameId | generatedInputFrameId | toApplyInputFrameId
|
||||
|
@@ -2,9 +2,11 @@
|
||||
|
||||
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md).
|
||||
|
||||

|
||||
_(the following gif is sped up to ~1.5x for file size reduction, kindly note that animations are resumed from a partial progress)_
|
||||
|
||||
Please also checkout [this demo video](https://pan.baidu.com/s/1YkfuHjNLzlFVnKiEj6wrDQ?pwd=tkr5) to see how this demo carries out a full 60fps synchronization with the help of _batched input upsync/downsync_ for satisfying network I/O performance.
|
||||

|
||||
|
||||
Please also checkout [this demo video](https://pan.baidu.com/s/1Lmot9cb0pYylfUvC8G4fDg?pwd=ia97) to see how this demo carries out a full 60fps synchronization with the help of _batched input upsync/downsync_ for satisfying network I/O performance.
|
||||
|
||||
The video mainly shows the following features.
|
||||
- The backend receives inputs from frontend peers and broadcasts back for synchronization.
|
||||
|
@@ -1,5 +1,6 @@
|
||||
PROJECTNAME=server.exe
|
||||
ROOT_DIR=.
|
||||
GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
all: help
|
||||
|
||||
gen-constants:
|
||||
@@ -13,13 +14,13 @@ run-test-and-hotreload:
|
||||
ServerEnv=TEST CompileDaemon -log-prefix=false -build="go build" -command="./$(PROJECTNAME)"
|
||||
|
||||
build:
|
||||
go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
GOPROXY=$(GOPROXY) go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
run-prod: build-prod
|
||||
./$(PROJECTNAME)
|
||||
|
||||
build-prod:
|
||||
go build -ldflags "-s -w -X main.VERSION=$(shell git rev-parse --short HEAD)-$(shell date "+%Y%m%d-%H:%M:%S")" -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
GOPROXY=$(GOPROXY) go build -ldflags "-s -w -X main.VERSION=$(shell git rev-parse --short HEAD)-$(shell date "+%Y%m%d-%H:%M:%S")" -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
.PHONY: help
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
@@ -526,8 +527,10 @@ func (p *playerController) maybeCreatePlayerWechatAuthBinding(userInfo utils.Use
|
||||
}
|
||||
if player != nil {
|
||||
updateInfo := models.Player{
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
DisplayName: userInfo.Nickname,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
DisplayName: userInfo.Nickname,
|
||||
},
|
||||
}
|
||||
tx := storage.MySQLManagerIns.MustBegin()
|
||||
defer tx.Rollback()
|
||||
@@ -542,10 +545,12 @@ func (p *playerController) maybeCreatePlayerWechatAuthBinding(userInfo utils.Use
|
||||
}
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
return p.createNewPlayer(player, userInfo.OpenID, int(Constants.AuthChannel.Wechat))
|
||||
}
|
||||
@@ -562,8 +567,10 @@ func (p *playerController) maybeCreatePlayerWechatGameAuthBinding(userInfo utils
|
||||
}
|
||||
if player != nil {
|
||||
updateInfo := models.Player{
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
DisplayName: userInfo.Nickname,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
DisplayName: userInfo.Nickname,
|
||||
},
|
||||
}
|
||||
tx := storage.MySQLManagerIns.MustBegin()
|
||||
defer tx.Rollback()
|
||||
@@ -578,10 +585,12 @@ func (p *playerController) maybeCreatePlayerWechatGameAuthBinding(userInfo utils
|
||||
}
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
return p.createNewPlayer(player, userInfo.OpenID, int(Constants.AuthChannel.WechatGame))
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
@@ -71,7 +72,6 @@ func createMysqlData(rows *sqlx.Rows, v string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 加上tableName参数, 用于pre_conf_data.sqlite里bot_player表的复用 --kobako
|
||||
func maybeCreateNewPlayerFromBotTable(db *sqlx.DB, tableName string) {
|
||||
var ls []*dbBotPlayer
|
||||
err := db.Select(&ls, "SELECT name, magic_phone_country_code, magic_phone_num, display_name FROM "+tableName)
|
||||
@@ -88,7 +88,6 @@ func maybeCreateNewPlayerFromBotTable(db *sqlx.DB, tableName string) {
|
||||
panic(err)
|
||||
}
|
||||
query = storage.MySQLManagerIns.Rebind(query)
|
||||
// existNames := make([]string, len(ls), len(ls))
|
||||
var existPlayers []*models.Player
|
||||
err = storage.MySQLManagerIns.Select(&existPlayers, query, args...)
|
||||
if nil != err {
|
||||
@@ -99,13 +98,11 @@ func maybeCreateNewPlayerFromBotTable(db *sqlx.DB, tableName string) {
|
||||
var flag bool
|
||||
for _, v := range existPlayers {
|
||||
if botPlayer.Name == v.Name {
|
||||
// 已有数据,合并处理
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !flag {
|
||||
// 找不到,新增
|
||||
Logger.Debug("create", zap.Any(tableName, botPlayer))
|
||||
err := createNewBotPlayer(botPlayer)
|
||||
if err != nil {
|
||||
@@ -120,11 +117,14 @@ func createNewBotPlayer(p *dbBotPlayer) error {
|
||||
defer tx.Rollback()
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Name: p.Name,
|
||||
DisplayName: p.DisplayName,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Name: p.Name,
|
||||
DisplayName: p.DisplayName,
|
||||
},
|
||||
}
|
||||
|
||||
err := player.Insert(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
|
||||
@@ -75,9 +76,11 @@ func createNewPlayer(p *dbTestPlayer) error {
|
||||
defer tx.Rollback()
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Name: p.Name,
|
||||
},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Name: p.Name,
|
||||
}
|
||||
err := player.Insert(tx)
|
||||
if err != nil {
|
||||
|
@@ -2,10 +2,9 @@ package models
|
||||
|
||||
import (
|
||||
. "battle_srv/protos"
|
||||
. "dnmshared/sharedprotos"
|
||||
)
|
||||
|
||||
func toPbPlayers(modelInstances map[int32]*Player) map[int32]*PlayerDownsync {
|
||||
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*PlayerDownsync {
|
||||
toRet := make(map[int32]*PlayerDownsync, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
@@ -13,18 +12,26 @@ func toPbPlayers(modelInstances map[int32]*Player) map[int32]*PlayerDownsync {
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &PlayerDownsync{
|
||||
Id: last.Id,
|
||||
VirtualGridX: last.VirtualGridX,
|
||||
VirtualGridY: last.VirtualGridY,
|
||||
Dir: &Direction{
|
||||
Dx: last.Dir.Dx,
|
||||
Dy: last.Dir.Dy,
|
||||
},
|
||||
Speed: last.Speed,
|
||||
BattleState: last.BattleState,
|
||||
Score: last.Score,
|
||||
Removed: last.Removed,
|
||||
JoinIndex: last.JoinIndex,
|
||||
Id: last.Id,
|
||||
VirtualGridX: last.VirtualGridX,
|
||||
VirtualGridY: last.VirtualGridY,
|
||||
DirX: last.DirX,
|
||||
DirY: last.DirY,
|
||||
VelX: last.VelX,
|
||||
VelY: last.VelY,
|
||||
Speed: last.Speed,
|
||||
BattleState: last.BattleState,
|
||||
CharacterState: last.CharacterState,
|
||||
InAir: last.InAir,
|
||||
JoinIndex: last.JoinIndex,
|
||||
ColliderRadius: last.ColliderRadius,
|
||||
Score: last.Score,
|
||||
Removed: last.Removed,
|
||||
}
|
||||
if withMetaInfo {
|
||||
toRet[k].Name = last.Name
|
||||
toRet[k].DisplayName = last.DisplayName
|
||||
toRet[k].Avatar = last.Avatar
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,19 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
. "dnmshared/sharedprotos"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type PlayerBattleState struct {
|
||||
ADDED_PENDING_BATTLE_COLLIDER_ACK int32
|
||||
READDED_PENDING_BATTLE_COLLIDER_ACK int32
|
||||
READDED_BATTLE_COLLIDER_ACKED int32
|
||||
ACTIVE int32
|
||||
DISCONNECTED int32
|
||||
LOST int32
|
||||
@@ -24,21 +27,17 @@ func InitPlayerBattleStateIns() {
|
||||
PlayerBattleStateIns = PlayerBattleState{
|
||||
ADDED_PENDING_BATTLE_COLLIDER_ACK: 0,
|
||||
READDED_PENDING_BATTLE_COLLIDER_ACK: 1,
|
||||
ACTIVE: 2,
|
||||
DISCONNECTED: 3,
|
||||
LOST: 4,
|
||||
EXPELLED_DURING_GAME: 5,
|
||||
EXPELLED_IN_DISMISSAL: 6,
|
||||
READDED_BATTLE_COLLIDER_ACKED: 2,
|
||||
ACTIVE: 3,
|
||||
DISCONNECTED: 4,
|
||||
LOST: 5,
|
||||
EXPELLED_DURING_GAME: 6,
|
||||
EXPELLED_IN_DISMISSAL: 7,
|
||||
}
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
// Meta info fields
|
||||
Id int32 `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
DisplayName string `json:"displayName,omitempty" db:"display_name"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
ColliderRadius float64 `json:"-"`
|
||||
PlayerDownsync
|
||||
|
||||
// DB only fields
|
||||
CreatedAt int64 `db:"created_at"`
|
||||
@@ -46,19 +45,10 @@ type Player struct {
|
||||
DeletedAt NullInt64 `db:"deleted_at"`
|
||||
TutorialStage int `db:"tutorial_stage"`
|
||||
|
||||
// in-battle info fields
|
||||
VirtualGridX int32
|
||||
VirtualGridY int32
|
||||
Dir *Direction
|
||||
Speed int32
|
||||
BattleState int32
|
||||
LastMoveGmtMillis int32
|
||||
Score int32
|
||||
Removed bool
|
||||
JoinIndex int32
|
||||
// other in-battle info fields
|
||||
LastSentInputFrameId int32
|
||||
AckingFrameId int32
|
||||
AckingInputFrameId int32
|
||||
LastSentInputFrameId int32
|
||||
}
|
||||
|
||||
func ExistPlayerByName(name string) (bool, error) {
|
||||
@@ -74,15 +64,43 @@ func GetPlayerById(id int) (*Player, error) {
|
||||
}
|
||||
|
||||
func getPlayer(cond sq.Eq) (*Player, error) {
|
||||
var p Player
|
||||
err := getObj("player", cond, &p)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
p := Player{}
|
||||
pd := PlayerDownsync{}
|
||||
query, args, err := sq.Select("*").From("player").Where(cond).Limit(1).ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Dir = &Direction{
|
||||
Dx: 0,
|
||||
Dy: 0,
|
||||
rows, err := storage.MySQLManagerIns.Queryx(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cols, err := rows.Columns()
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
for rows.Next() {
|
||||
// TODO: Do it more elegantly, but by now I don't have time to learn reflection of Golang
|
||||
vals := rowValues(rows, cols)
|
||||
for i, col := range cols {
|
||||
val := *vals[i].(*interface{})
|
||||
if "id" == col {
|
||||
pd.Id = int32(val.(int64))
|
||||
}
|
||||
if "name" == col {
|
||||
switch v := val.(type) {
|
||||
case []byte:
|
||||
pd.Name = string(v)
|
||||
default:
|
||||
pd.Name = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
if "created_at" == col {
|
||||
p.CreatedAt = int64(val.(int64))
|
||||
}
|
||||
}
|
||||
Logger.Debug("Queried player from db", zap.Any("cond", cond), zap.Any("p", p), zap.Any("pd", pd), zap.Any("cols", cols), zap.Any("rowValues", vals))
|
||||
}
|
||||
p.PlayerDownsync = pd
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
@@ -113,8 +131,6 @@ func Update(tx *sqlx.Tx, id int32, p *Player) (bool, error) {
|
||||
}
|
||||
result, err := tx.Exec(query, args...)
|
||||
if err != nil {
|
||||
fmt.Println("ERRRRRRR: ")
|
||||
fmt.Println(err)
|
||||
return false, err
|
||||
}
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
|
@@ -10,6 +10,17 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func rowValues(rows *sqlx.Rows, cols []string) []interface{} {
|
||||
results := make([]interface{}, len(cols))
|
||||
for i := range results {
|
||||
results[i] = new(interface{})
|
||||
}
|
||||
if err := rows.Scan(results[:]...); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func exist(t string, cond sq.Eq) (bool, error) {
|
||||
c, err := getCount(t, cond)
|
||||
if err != nil {
|
||||
|
@@ -21,6 +21,10 @@ func NewRingBuffer(n int32) *RingBuffer {
|
||||
}
|
||||
|
||||
func (rb *RingBuffer) Put(pItem interface{}) {
|
||||
for 0 < rb.Cnt && rb.Cnt >= rb.N {
|
||||
// Make room for the new element
|
||||
rb.Pop()
|
||||
}
|
||||
rb.Eles[rb.Ed] = pItem
|
||||
rb.EdFrameId++
|
||||
rb.Cnt++
|
||||
@@ -69,5 +73,8 @@ func (rb *RingBuffer) GetByOffset(offsetFromSt int32) interface{} {
|
||||
}
|
||||
|
||||
func (rb *RingBuffer) GetByFrameId(frameId int32) interface{} {
|
||||
if frameId >= rb.EdFrameId || frameId < rb.StFrameId {
|
||||
return nil
|
||||
}
|
||||
return rb.GetByOffset(frameId - rb.StFrameId)
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -21,11 +22,13 @@ var (
|
||||
|
||||
func (pPq *RoomHeap) PrintInOrder() {
|
||||
pq := *pPq
|
||||
fmt.Printf("The RoomHeap instance now contains:\n")
|
||||
s := make([]string, 0)
|
||||
s = append(s, fmt.Sprintf("The RoomHeap instance now contains:"))
|
||||
for i := 0; i < len(pq); i++ {
|
||||
fmt.Printf("{index: %d, roomID: %d, score: %.2f} ", i, pq[i].Id, pq[i].Score)
|
||||
s = append(s, fmt.Sprintf("{index: %d, roomID: %d, score: %.2f} ", i, pq[i].Id, pq[i].Score))
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
Logger.Debug(strings.Join(s, "\n"))
|
||||
}
|
||||
|
||||
func (pq RoomHeap) Len() int { return len(pq) }
|
||||
|
@@ -16,7 +16,6 @@ import (
|
||||
"time"
|
||||
|
||||
. "dnmshared"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -47,9 +46,8 @@ func Serve(c *gin.Context) {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Logger.Info("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token))
|
||||
boundRoomId := 0
|
||||
expectRoomId := 0
|
||||
expectedRoomId := 0
|
||||
var err error
|
||||
if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId {
|
||||
boundRoomId, err = strconv.Atoi(boundRoomIdStr)
|
||||
@@ -58,27 +56,28 @@ func Serve(c *gin.Context) {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Logger.Info("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
|
||||
}
|
||||
if expectRoomIdStr, hasExpectRoomId := c.GetQuery("expectedRoomId"); hasExpectRoomId {
|
||||
expectRoomId, err = strconv.Atoi(expectRoomIdStr)
|
||||
Logger.Debug("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
|
||||
} else if expectedRoomIdStr, hasExpectRoomId := c.GetQuery("expectedRoomId"); hasExpectRoomId {
|
||||
expectedRoomId, err = strconv.Atoi(expectedRoomIdStr)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Logger.Info("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("expectedRoomId", expectRoomId))
|
||||
Logger.Debug("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("expectedRoomId", expectedRoomId))
|
||||
} else {
|
||||
Logger.Debug("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token))
|
||||
}
|
||||
|
||||
// TODO: Wrap the following 2 stmts by sql transaction!
|
||||
playerId, err := models.GetPlayerIdByToken(token)
|
||||
if err != nil || playerId == 0 {
|
||||
// TODO: Abort with specific message.
|
||||
Logger.Info("PlayerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
|
||||
Logger.Warn("PlayerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
Logger.Info("PlayerLogin record has been found for ws authentication:", zap.Any("playerId", playerId))
|
||||
Logger.Info("PlayerLogin record has been found for ws authentication:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId), zap.Any("expectedRoomId", expectedRoomId))
|
||||
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
@@ -160,14 +159,14 @@ func Serve(c *gin.Context) {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotFound, "")
|
||||
}
|
||||
|
||||
Logger.Info("Player has logged in and its profile is found from persistent storage:", zap.Any("playerId", playerId), zap.Any("play", pPlayer))
|
||||
Logger.Debug("Player has logged in and its profile is found from persistent storage:", zap.Any("playerId", playerId), zap.Any("player", pPlayer))
|
||||
|
||||
// Find a room to join.
|
||||
Logger.Info("About to acquire RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
Logger.Debug("About to acquire RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
(*(models.RoomHeapMux)).Lock()
|
||||
defer func() {
|
||||
(*(models.RoomHeapMux)).Unlock()
|
||||
Logger.Info("Released RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
Logger.Debug("Released RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
}()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -175,13 +174,12 @@ func Serve(c *gin.Context) {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "")
|
||||
}
|
||||
}()
|
||||
Logger.Info("Acquired RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
Logger.Debug("Acquired RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
// Logger.Info("The RoomHeapManagerIns has:", zap.Any("addr", fmt.Sprintf("%p", models.RoomHeapManagerIns)), zap.Any("size", len(*(models.RoomHeapManagerIns))))
|
||||
playerSuccessfullyAddedToRoom := false
|
||||
if 0 < boundRoomId {
|
||||
if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; existent {
|
||||
pRoom = tmpPRoom
|
||||
Logger.Info("Successfully got:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forBoundRoomId", boundRoomId))
|
||||
res := pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
|
||||
if !res {
|
||||
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forBoundRoomId", boundRoomId))
|
||||
@@ -189,19 +187,16 @@ func Serve(c *gin.Context) {
|
||||
playerSuccessfullyAddedToRoom = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < expectRoomId {
|
||||
if tmpRoom, existent := (*models.RoomMapManagerIns)[int32(expectRoomId)]; existent {
|
||||
} else if 0 < expectedRoomId {
|
||||
if tmpRoom, existent := (*models.RoomMapManagerIns)[int32(expectedRoomId)]; existent {
|
||||
pRoom = tmpRoom
|
||||
Logger.Info("Successfully got:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectRoomId))
|
||||
|
||||
if pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
||||
playerSuccessfullyAddedToRoom = true
|
||||
} else if pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
||||
playerSuccessfullyAddedToRoom = true
|
||||
} else {
|
||||
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectRoomId))
|
||||
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectedRoomId))
|
||||
playerSuccessfullyAddedToRoom = false
|
||||
}
|
||||
|
||||
@@ -221,7 +216,7 @@ func Serve(c *gin.Context) {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.LocallyNoAvailableRoom, fmt.Sprintf("Cannot pop a (*Room) for playerId == %v!", playerId))
|
||||
} else {
|
||||
pRoom = tmpRoom
|
||||
Logger.Info("Successfully popped:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId))
|
||||
Logger.Info("Successfully popped:\n", zap.Any("roomId", pRoom.Id), zap.Any("forPlayerId", playerId))
|
||||
res := pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
|
||||
if !res {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotAddableToRoom, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId))
|
||||
@@ -247,8 +242,8 @@ func Serve(c *gin.Context) {
|
||||
bciFrame := &pb.BattleColliderInfo{
|
||||
BoundRoomId: pRoom.Id,
|
||||
StageName: pRoom.StageName,
|
||||
StrToVec2DListMap: pRoom.RawBattleStrToVec2DListMap,
|
||||
StrToPolygon2DListMap: pRoom.RawBattleStrToPolygon2DListMap,
|
||||
StrToVec2DListMap: pRoom.StrToVec2DListMap,
|
||||
StrToPolygon2DListMap: pRoom.StrToPolygon2DListMap,
|
||||
StageDiscreteW: pRoom.StageDiscreteW,
|
||||
StageDiscreteH: pRoom.StageDiscreteH,
|
||||
StageTileW: pRoom.StageTileW,
|
||||
@@ -269,6 +264,15 @@ func Serve(c *gin.Context) {
|
||||
|
||||
WorldToVirtualGridRatio: pRoom.WorldToVirtualGridRatio,
|
||||
VirtualGridToWorldRatio: pRoom.VirtualGridToWorldRatio,
|
||||
|
||||
SpAtkLookupFrames: pRoom.SpAtkLookupFrames,
|
||||
RenderCacheSize: pRoom.RenderCacheSize,
|
||||
MeleeSkillConfig: pRoom.MeleeSkillConfig,
|
||||
SnapIntoPlatformOverlap: pRoom.SnapIntoPlatformOverlap,
|
||||
SnapIntoPlatformThreshold: pRoom.SnapIntoPlatformThreshold,
|
||||
JumpingInitVelY: pRoom.JumpingInitVelY,
|
||||
GravityX: pRoom.GravityX,
|
||||
GravityY: pRoom.GravityY,
|
||||
}
|
||||
|
||||
resp := &pb.WsResp{
|
||||
@@ -357,7 +361,7 @@ func Serve(c *gin.Context) {
|
||||
receivingLoopAgainstPlayer := func() error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
Logger.Error("Goroutine `receivingLoopAgainstPlayer`, recovery spot#1, recovered from: ", zap.Any("panic", r), zap.Any("callstack", debug.Stack()))
|
||||
Logger.Error("Goroutine `receivingLoopAgainstPlayer`, recovery spot#1, recovered from: ", zap.Any("panic", r))
|
||||
}
|
||||
Logger.Info("Goroutine `receivingLoopAgainstPlayer` is stopped for:", zap.Any("playerId", playerId), zap.Any("roomId", pRoom.Id))
|
||||
}()
|
||||
@@ -366,7 +370,7 @@ func Serve(c *gin.Context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tries to receive from client-side in a non-blocking manner.
|
||||
// TODO: Is there any potential edge-trigger improvement like the epoll approach mentioned above for the following statement? See discussion in https://github.com/gorilla/websocket/issues/122
|
||||
_, bytes, err := conn.ReadMessage()
|
||||
if nil != err {
|
||||
Logger.Error("About to `signalToCloseConnOfThisPlayer`", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Error(err))
|
||||
|
BIN
charts/AttackTriggerCases.jpg
Normal file
After Width: | Height: | Size: 176 KiB |
@@ -1,3 +1,8 @@
|
||||
# Double playback speed of a video
|
||||
```
|
||||
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" output.mp4
|
||||
```
|
||||
|
||||
# GIF creation cmd reference
|
||||
```
|
||||
ffmpeg -ss 12 -t 13 -i input.mp4 -vf "fps=10,scale=480:-1" -loop 0 output.gif
|
||||
|
Before Width: | Height: | Size: 2.7 MiB |
BIN
charts/jump_sync_spedup.gif
Normal file
After Width: | Height: | Size: 11 MiB |
@@ -5,7 +5,7 @@ all: help
|
||||
GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
|
||||
build:
|
||||
go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
GOPROXY=$(GOPROXY) go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
run: build
|
||||
./$(PROJECTNAME)
|
||||
|
@@ -4,6 +4,7 @@ go 1.19
|
||||
|
||||
require (
|
||||
dnmshared v0.0.0
|
||||
battle_srv v0.0.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/hajimehoshi/ebiten/v2 v2.4.7
|
||||
github.com/solarlune/resolv v0.5.1
|
||||
@@ -26,3 +27,4 @@ require (
|
||||
)
|
||||
|
||||
replace dnmshared => ../dnmshared
|
||||
replace battle_srv => ../battle_srv
|
||||
|
@@ -85,8 +85,9 @@ type Game struct {
|
||||
|
||||
func NewGame() *Game {
|
||||
|
||||
stageName := "simple" // Use this for calibration
|
||||
// stageName := "simple" // Use this for calibration in isometric orientation
|
||||
// stageName := "richsoil"
|
||||
stageName := "dungeon"
|
||||
stageDiscreteW, stageDiscreteH, stageTileW, stageTileH, playerPosMap, barrierMap, err := parseStage(stageName)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
. "battle_srv/protos"
|
||||
. "dnmshared"
|
||||
. "dnmshared/sharedprotos"
|
||||
"fmt"
|
||||
@@ -33,15 +34,19 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
spaceOffsetX := float64(spaceW) * 0.5
|
||||
spaceOffsetY := float64(spaceH) * 0.5
|
||||
|
||||
virtualGridToWorldRatio := 0.1
|
||||
playerDefaultSpeed := 20
|
||||
minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 2)
|
||||
playerColliderRadius := float64(24)
|
||||
worldToVirtualGridRatio := float64(1000)
|
||||
virtualGridToWorldRatio := float64(1) / worldToVirtualGridRatio
|
||||
playerDefaultSpeed := 1 * worldToVirtualGridRatio
|
||||
minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 3)
|
||||
playerColliderRadius := float64(12)
|
||||
playerColliders := make([]*resolv.Object, len(playerPosList.Eles))
|
||||
snapIntoPlatformOverlap := float64(0.1)
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep)
|
||||
topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
|
||||
for i, playerPos := range playerPosList.Eles {
|
||||
playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
|
||||
Logger.Info(fmt.Sprintf("Player Collider#%d: player world pos =(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
||||
playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
|
||||
Logger.Info(fmt.Sprintf("Player Collider#%d: player world pos=(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
playerColliders[i] = playerCollider
|
||||
space.Add(playerCollider)
|
||||
}
|
||||
@@ -49,7 +54,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
barrierLocalId := 0
|
||||
for _, barrierUnaligned := range barrierList.Eles {
|
||||
barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, "Barrier")
|
||||
Logger.Info(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
Logger.Debug(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
space.Add(barrierCollider)
|
||||
barrierLocalId++
|
||||
}
|
||||
@@ -58,24 +63,26 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
|
||||
moveToCollide := true
|
||||
if moveToCollide {
|
||||
newVx, newVy := int32(-2959), int32(-2261)
|
||||
effPushback := Vec2D{X: float64(0), Y: float64(0)}
|
||||
toTestPlayerCollider := playerColliders[0]
|
||||
toTestPlayerCollider.X, toTestPlayerCollider.Y = VirtualGridToPolygonColliderAnchorPos(newVx, newVy, playerColliderRadius, playerColliderRadius, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
|
||||
//colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
||||
//newVx, newVy := int32(27999), int32(-420270)
|
||||
//toTestPlayerCollider.X, toTestPlayerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
|
||||
|
||||
Logger.Info(fmt.Sprintf("Checking collision for virtual (%d, %d), now playerShape=%v", newVx, newVy, ConvexPolygonStr(toTestPlayerCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
Logger.Info(fmt.Sprintf("Checking collision for playerShape=%v", ConvexPolygonStr(toTestPlayerCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
|
||||
toTestPlayerCollider.Update()
|
||||
if collision := toTestPlayerCollider.Check(0, 0); collision != nil {
|
||||
playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon)
|
||||
for _, obj := range collision.Objects {
|
||||
barrierShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY))
|
||||
bShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
Logger.Warn(fmt.Sprintf("Checking potential: a=%v, b=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape)))
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape), pushbackX, pushbackY))
|
||||
effPushback.X += pushbackX
|
||||
effPushback.Y += pushbackY
|
||||
} else {
|
||||
Logger.Warn(fmt.Sprintf("Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), overlapResult))
|
||||
Logger.Warn(fmt.Sprintf("Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape), overlapResult))
|
||||
}
|
||||
}
|
||||
toTestPlayerCollider.X -= effPushback.X
|
||||
@@ -84,6 +91,74 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
Logger.Info(fmt.Sprintf("effPushback={%v, %v}", effPushback.X, effPushback.Y))
|
||||
}
|
||||
}
|
||||
meleeBullet := &MeleeBullet{
|
||||
// for offender
|
||||
StartupFrames: int32(18),
|
||||
ActiveFrames: int32(1),
|
||||
RecoveryFrames: int32(61),
|
||||
RecoveryFramesOnBlock: int32(61),
|
||||
RecoveryFramesOnHit: int32(61),
|
||||
Moveforward: &Vec2D{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
},
|
||||
HitboxOffset: float64(24.0),
|
||||
HitboxSize: &Vec2D{
|
||||
X: float64(45.0),
|
||||
Y: float64(32.0),
|
||||
},
|
||||
|
||||
// for defender
|
||||
HitStunFrames: int32(18),
|
||||
BlockStunFrames: int32(9),
|
||||
Pushback: float64(22.0),
|
||||
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
|
||||
Damage: int32(5),
|
||||
}
|
||||
bulletLeftToRight := false
|
||||
if bulletLeftToRight {
|
||||
xfac := float64(1.0)
|
||||
offenderWx, offenderWy := playerPosList.Eles[0].X, playerPosList.Eles[0].Y
|
||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "MeleeBullet")
|
||||
space.Add(newBulletCollider)
|
||||
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||
Logger.Warn(fmt.Sprintf("bullet ->: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
||||
|
||||
if collision := newBulletCollider.Check(0, 0); collision != nil {
|
||||
for _, obj := range collision.Objects {
|
||||
objShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, bulletShape, objShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("bullet ->: Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), pushbackX, pushbackY))
|
||||
} else {
|
||||
Logger.Warn(fmt.Sprintf("bullet ->: Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), overlapResult))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bulletRightToLeft := false
|
||||
if bulletRightToLeft {
|
||||
xfac := float64(-1.0)
|
||||
offenderWx, offenderWy := playerPosList.Eles[1].X, playerPosList.Eles[1].Y
|
||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||
|
||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "MeleeBullet")
|
||||
space.Add(newBulletCollider)
|
||||
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||
Logger.Warn(fmt.Sprintf("bullet <-: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
||||
|
||||
if collision := newBulletCollider.Check(0, 0); collision != nil {
|
||||
for _, obj := range collision.Objects {
|
||||
objShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, bulletShape, objShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("bullet <-: Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), pushbackX, pushbackY))
|
||||
} else {
|
||||
Logger.Warn(fmt.Sprintf("bullet <-: Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), overlapResult))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return world
|
||||
}
|
||||
@@ -98,13 +173,16 @@ func (world *WorldColliderDisplay) Draw(screen *ebiten.Image) {
|
||||
if o.HasTags("Player") {
|
||||
drawColor := color.RGBA{0, 255, 0, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
} else if o.HasTags("MeleeBullet") {
|
||||
drawColor := color.RGBA{0, 0, 255, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
} else {
|
||||
drawColor := color.RGBA{60, 60, 60, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
}
|
||||
}
|
||||
|
||||
world.Game.DebugDraw(screen, world.Space)
|
||||
//world.Game.DebugDraw(screen, world.Space)
|
||||
|
||||
if world.Game.ShowHelpText {
|
||||
|
||||
|
@@ -10,33 +10,33 @@ func NormVec2D(dx, dy float64) Vec2D {
|
||||
}
|
||||
|
||||
func AlignPolygon2DToBoundingBox(input *Polygon2D) *Polygon2D {
|
||||
// Transform again to put "anchor" at the top-left point of the bounding box for "resolv"
|
||||
boundingBoxTL := &Vec2D{
|
||||
// Transform again to put "anchor" at the "bottom-left point (w.r.t. world space)" of the bounding box for "resolv"
|
||||
boundingBoxBL := &Vec2D{
|
||||
X: math.MaxFloat64,
|
||||
Y: math.MaxFloat64,
|
||||
}
|
||||
for _, p := range input.Points {
|
||||
if p.X < boundingBoxTL.X {
|
||||
boundingBoxTL.X = p.X
|
||||
if p.X < boundingBoxBL.X {
|
||||
boundingBoxBL.X = p.X
|
||||
}
|
||||
if p.Y < boundingBoxTL.Y {
|
||||
boundingBoxTL.Y = p.Y
|
||||
if p.Y < boundingBoxBL.Y {
|
||||
boundingBoxBL.Y = p.Y
|
||||
}
|
||||
}
|
||||
|
||||
// Now "input.Anchor" should move to "input.Anchor+boundingBoxTL", thus "boundingBoxTL" is also the value of the negative diff for all "input.Points"
|
||||
// Now "input.Anchor" should move to "input.Anchor+boundingBoxBL", thus "boundingBoxBL" is also the value of the negative diff for all "input.Points"
|
||||
output := &Polygon2D{
|
||||
Anchor: &Vec2D{
|
||||
X: input.Anchor.X + boundingBoxTL.X,
|
||||
Y: input.Anchor.Y + boundingBoxTL.Y,
|
||||
X: input.Anchor.X + boundingBoxBL.X,
|
||||
Y: input.Anchor.Y + boundingBoxBL.Y,
|
||||
},
|
||||
Points: make([]*Vec2D, len(input.Points)),
|
||||
}
|
||||
|
||||
for i, p := range input.Points {
|
||||
output.Points[i] = &Vec2D{
|
||||
X: p.X - boundingBoxTL.X,
|
||||
Y: p.Y - boundingBoxTL.Y,
|
||||
X: p.X - boundingBoxBL.X,
|
||||
Y: p.Y - boundingBoxBL.Y,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,9 +18,17 @@ func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
|
||||
return fmt.Sprintf("{\n%s\n}", strings.Join(s, ",\n"))
|
||||
}
|
||||
|
||||
func GenerateRectCollider(origX, origY, w, h, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||
cx, cy := WorldToPolygonColliderAnchorPos(origX, origY, w*0.5, h*0.5, spaceOffsetX, spaceOffsetY)
|
||||
collider := resolv.NewObject(cx, cy, w, h, tag)
|
||||
func RectCenterStr(body *resolv.Object, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64) string {
|
||||
return fmt.Sprintf("{%.2f, %.2f}", body.X + leftPadding + halfBoundingW - spaceOffsetX, body.Y + bottomPadding + halfBoundingH - spaceOffsetY)
|
||||
}
|
||||
|
||||
func GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||
blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY)
|
||||
return generateRectColliderInCollisionSpace(blX, blY, leftPadding+w+rightPadding, bottomPadding+h+topPadding, tag)
|
||||
}
|
||||
|
||||
func generateRectColliderInCollisionSpace(blX, blY, w, h float64, tag string) *resolv.Object {
|
||||
collider := resolv.NewObject(blX, blY, w, h, tag) // Unlike its frontend counter part, the position of a "resolv.Object" must be specified by "bottom-left point" because "w" and "h" must be positive, see "resolv.Object.BoundsToSpace" for details
|
||||
shape := resolv.NewRectangle(0, 0, w, h)
|
||||
collider.SetShape(shape)
|
||||
return collider
|
||||
@@ -62,6 +70,7 @@ func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.Conve
|
||||
playerShape.SetPosition(origX, origY)
|
||||
}()
|
||||
playerShape.SetPosition(origX+oldDx, origY+oldDy)
|
||||
|
||||
overlapResult := &SatResult{
|
||||
Overlap: 0,
|
||||
OverlapX: 0,
|
||||
@@ -70,7 +79,7 @@ func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.Conve
|
||||
BContainedInA: true,
|
||||
Axis: vector.Vector{0, 0},
|
||||
}
|
||||
if overlapped := IsPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
|
||||
if overlapped := isPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
|
||||
pushbackX, pushbackY := overlapResult.Overlap*overlapResult.OverlapX, overlapResult.Overlap*overlapResult.OverlapY
|
||||
return true, pushbackX, pushbackY, overlapResult
|
||||
} else {
|
||||
@@ -87,16 +96,17 @@ type SatResult struct {
|
||||
Axis vector.Vector
|
||||
}
|
||||
|
||||
func IsPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
|
||||
func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
|
||||
aCnt, bCnt := len(a.Points), len(b.Points)
|
||||
// Single point case
|
||||
if 1 == aCnt && 1 == bCnt {
|
||||
if nil != result {
|
||||
result.Overlap = 0
|
||||
}
|
||||
return a.Points[0].X() == b.Points[0].X() && a.Points[0].Y() == b.Points[0].Y()
|
||||
return a.Points[0][0] == b.Points[0][0] && a.Points[0][1] == b.Points[0][1]
|
||||
}
|
||||
|
||||
//Logger.Info(fmt.Sprintf("Checking collision between a=%v, b=%v", ConvexPolygonStr(a), ConvexPolygonStr(b)))
|
||||
if 1 < aCnt {
|
||||
for _, axis := range a.SATAxes() {
|
||||
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
|
||||
@@ -112,6 +122,7 @@ func IsPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool
|
||||
}
|
||||
}
|
||||
}
|
||||
//Logger.Info(fmt.Sprintf("a=%v and b=%v are overlapped", ConvexPolygonStr(a), ConvexPolygonStr(b)))
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -133,9 +144,10 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
|
||||
e = (-2.98, 1.49).Unit()
|
||||
*/
|
||||
|
||||
//Logger.Info(fmt.Sprintf("Checking separation between a=%v, b=%v along axis e={%.3f, %.3f}#1", ConvexPolygonStr(a), ConvexPolygonStr(b), e[0], e[1]))
|
||||
var aStart, aEnd, bStart, bEnd float64 = math.MaxFloat64, -math.MaxFloat64, math.MaxFloat64, -math.MaxFloat64
|
||||
for _, p := range a.Points {
|
||||
dot := (p.X()+a.X)*e.X() + (p.Y()+a.Y)*e.Y()
|
||||
dot := (p[0]+a.X)*e[0] + (p[1]+a.Y)*e[1]
|
||||
|
||||
if aStart > dot {
|
||||
aStart = dot
|
||||
@@ -147,7 +159,7 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
|
||||
}
|
||||
|
||||
for _, p := range b.Points {
|
||||
dot := (p.X()+b.X)*e.X() + (p.Y()+b.Y)*e.Y()
|
||||
dot := (p[0]+b.X)*e[0] + (p[1]+b.Y)*e[1]
|
||||
|
||||
if bStart > dot {
|
||||
bStart = dot
|
||||
@@ -164,7 +176,6 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
|
||||
}
|
||||
|
||||
if nil != result {
|
||||
result.Axis = e
|
||||
overlap := float64(0)
|
||||
|
||||
if aStart < bStart {
|
||||
@@ -205,16 +216,19 @@ func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, re
|
||||
absoluteOverlap = -overlap
|
||||
}
|
||||
|
||||
if 0 == currentOverlap || currentOverlap > absoluteOverlap {
|
||||
if (0 == result.Axis[0] && 0 == result.Axis[1]) || currentOverlap > absoluteOverlap {
|
||||
var sign float64 = 1
|
||||
if overlap < 0 {
|
||||
sign = -1
|
||||
}
|
||||
|
||||
result.Overlap = absoluteOverlap
|
||||
result.OverlapX = e.X() * sign
|
||||
result.OverlapY = e.Y() * sign
|
||||
result.OverlapX = e[0] * sign
|
||||
result.OverlapY = e[1] * sign
|
||||
}
|
||||
|
||||
result.Axis = e
|
||||
//Logger.Info(fmt.Sprintf("Checking separation between a=%v, b=%v along axis e={%.3f, %.3f}#2: aStart=%.3f, aEnd=%.3f, bStart=%.3f, bEnd=%.3f, overlap=%.3f, currentOverlap=%.3f, absoluteOverlap=%.3f, result=%v", ConvexPolygonStr(a), ConvexPolygonStr(b), e[0], e[1], aStart, aEnd, bStart, bEnd, overlap, currentOverlap, absoluteOverlap, result))
|
||||
}
|
||||
|
||||
// the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated
|
||||
@@ -236,20 +250,20 @@ func VirtualGridToWorldPos(vx, vy int32, virtualGridToWorldRatio float64) (float
|
||||
return wx, wy
|
||||
}
|
||||
|
||||
func WorldToPolygonColliderAnchorPos(wx, wy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
||||
return wx - halfBoundingW + collisionSpaceOffsetX, wy - halfBoundingH + collisionSpaceOffsetY
|
||||
func WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
||||
return wx - halfBoundingW - leftPadding + collisionSpaceOffsetX, wy - halfBoundingH - bottomPadding + collisionSpaceOffsetY
|
||||
}
|
||||
|
||||
func PolygonColliderAnchorToWorldPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
||||
return cx + halfBoundingW - collisionSpaceOffsetX, cy + halfBoundingH - collisionSpaceOffsetY
|
||||
func PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
|
||||
return cx + halfBoundingW + leftPadding - collisionSpaceOffsetX, cy + halfBoundingH + bottomPadding - collisionSpaceOffsetY
|
||||
}
|
||||
|
||||
func PolygonColliderAnchorToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) {
|
||||
wx, wy := PolygonColliderAnchorToWorldPos(cx, cy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||
func PolygonColliderBLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) {
|
||||
wx, wy := PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||
return WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio)
|
||||
}
|
||||
|
||||
func VirtualGridToPolygonColliderAnchorPos(vx, vy int32, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) {
|
||||
func VirtualGridToPolygonColliderBLPos(vx, vy int32, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) {
|
||||
wx, wy := VirtualGridToWorldPos(vx, vy, virtualGridToWorldRatio)
|
||||
return WorldToPolygonColliderAnchorPos(wx, wy, halfBoundingW, halfBoundingH, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||
return WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
@@ -43,13 +44,13 @@ type TmxOrTsxPolyline struct {
|
||||
|
||||
type TmxOrTsxObject struct {
|
||||
Id int `xml:"id,attr"`
|
||||
Gid *int `xml:"gid,attr"`
|
||||
Gid int `xml:"gid,attr"`
|
||||
X float64 `xml:"x,attr"`
|
||||
Y float64 `xml:"y,attr"`
|
||||
Properties *TmxOrTsxProperties `xml:"properties"`
|
||||
Polyline *TmxOrTsxPolyline `xml:"polyline"`
|
||||
Width *float64 `xml:"width,attr"`
|
||||
Height *float64 `xml:"height,attr"`
|
||||
Width float64 `xml:"width,attr"`
|
||||
Height float64 `xml:"height,attr"`
|
||||
}
|
||||
|
||||
type TmxOrTsxObjectGroup struct {
|
||||
@@ -376,13 +377,37 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
|
||||
}
|
||||
|
||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
||||
if nil == singleObjInTmxFile.Polyline {
|
||||
continue
|
||||
}
|
||||
if nil == singleObjInTmxFile.Properties.Property || "boundary_type" != singleObjInTmxFile.Properties.Property[0].Name || "barrier" != singleObjInTmxFile.Properties.Property[0].Value {
|
||||
continue
|
||||
}
|
||||
|
||||
if nil == singleObjInTmxFile.Polyline {
|
||||
pts := make([]*Vec2D, 4)
|
||||
s := make([]string, 0)
|
||||
pts[0] = &Vec2D{
|
||||
X: float64(0),
|
||||
Y: float64(0),
|
||||
}
|
||||
pts[1] = &Vec2D{
|
||||
X: float64(0),
|
||||
Y: singleObjInTmxFile.Height,
|
||||
}
|
||||
pts[2] = &Vec2D{
|
||||
X: singleObjInTmxFile.Width,
|
||||
Y: singleObjInTmxFile.Height,
|
||||
}
|
||||
pts[3] = &Vec2D{
|
||||
X: singleObjInTmxFile.Width,
|
||||
Y: float64(0),
|
||||
}
|
||||
for _, pt := range pts {
|
||||
s = append(s, fmt.Sprintf("%v,%v", pt.X, pt.Y))
|
||||
}
|
||||
singleObjInTmxFile.Polyline = &TmxOrTsxPolyline{
|
||||
Points: strings.Join(s, " "),
|
||||
}
|
||||
}
|
||||
|
||||
thePolygon2DInWorld, err := tmxPolylineToPolygon2D(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
@@ -406,6 +431,12 @@ type TileRectilinearSize struct {
|
||||
}
|
||||
|
||||
func (pTmxMapIns *TmxMap) continuousObjLayerVecToContinuousMapNodeVec(continuousObjLayerVec *Vec2D) Vec2D {
|
||||
if "orthogonal" == pTmxMapIns.Orientation {
|
||||
return Vec2D{
|
||||
X: continuousObjLayerVec.X,
|
||||
Y: -continuousObjLayerVec.Y,
|
||||
}
|
||||
}
|
||||
var tileRectilinearSize TileRectilinearSize
|
||||
tileRectilinearSize.Width = float64(pTmxMapIns.TileWidth)
|
||||
tileRectilinearSize.Height = float64(pTmxMapIns.TileHeight)
|
||||
@@ -428,18 +459,24 @@ func (pTmxMapIns *TmxMap) continuousObjLayerVecToContinuousMapNodeVec(continuous
|
||||
}
|
||||
|
||||
func (pTmxMapIns *TmxMap) continuousObjLayerOffsetToContinuousMapNodePos(continuousObjLayerOffset *Vec2D) Vec2D {
|
||||
layerOffset := Vec2D{
|
||||
X: 0,
|
||||
Y: float64(pTmxMapIns.Height*pTmxMapIns.TileHeight) * 0.5,
|
||||
var layerOffset Vec2D
|
||||
if "orthogonal" == pTmxMapIns.Orientation {
|
||||
layerOffset = Vec2D{
|
||||
X: -float64(pTmxMapIns.Width*pTmxMapIns.TileWidth) * 0.5,
|
||||
Y: float64(pTmxMapIns.Height*pTmxMapIns.TileHeight) * 0.5,
|
||||
}
|
||||
} else {
|
||||
// "isometric" == pTmxMapIns.Orientation
|
||||
layerOffset = Vec2D{
|
||||
X: 0,
|
||||
Y: float64(pTmxMapIns.Height*pTmxMapIns.TileHeight) * 0.5,
|
||||
}
|
||||
}
|
||||
|
||||
calibratedVec := continuousObjLayerOffset
|
||||
convertedVec := pTmxMapIns.continuousObjLayerVecToContinuousMapNodeVec(calibratedVec)
|
||||
convertedVec := pTmxMapIns.continuousObjLayerVecToContinuousMapNodeVec(continuousObjLayerOffset)
|
||||
|
||||
toRet := Vec2D{
|
||||
return Vec2D{
|
||||
X: layerOffset.X + convertedVec.X,
|
||||
Y: layerOffset.Y + convertedVec.Y,
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
BIN
dragonBonesProjects/SoldierElf.dbproj
Normal file
BIN
dragonBonesProjects/SoldierFireGhost.dbproj
Normal file
BIN
dragonBonesProjects/SoldierWaterGhost.dbproj
Normal file
1
dragonBonesProjects/library/SoldierElf.json
Normal file
@@ -0,0 +1 @@
|
||||
{"width":128,"imagePath":"SoldierElf_tex.png","height":128,"name":"SoldierElf","SubTexture":[{"frameHeight":45,"y":1,"frameX":0,"width":34,"frameY":0,"height":44,"name":"cape","frameWidth":34,"x":70},{"width":10,"y":107,"height":14,"name":"shouder_l","x":74},{"width":11,"y":107,"height":14,"name":"forearm_l","x":61},{"width":15,"y":93,"height":16,"name":"hand_l","x":1},{"width":30,"y":61,"height":30,"name":"weapon_hand_l","x":1},{"width":8,"y":101,"height":11,"name":"thigh_l","x":86},{"width":12,"y":93,"height":17,"name":"calf_l","x":18},{"width":20,"y":113,"height":8,"name":"foot_l","x":39},{"width":28,"y":61,"height":31,"name":"pelvis","x":33},{"width":8,"y":88,"height":11,"name":"thigh_r","x":77},{"width":12,"y":88,"height":17,"name":"calf_r","x":63},{"width":20,"y":113,"height":8,"name":"foot_r","x":17},{"width":13,"y":94,"height":12,"name":"shouder_r","x":45},{"width":67,"y":1,"height":58,"name":"chest","x":1},{"width":11,"y":94,"height":17,"name":"forearm_r","x":32},{"width":14,"y":111,"height":13,"name":"hand_r","x":1},{"frameHeight":39,"y":47,"frameX":-2,"width":34,"frameY":0,"height":39,"name":"we_bl_4_f_1","frameWidth":36,"x":70}]}
|
BIN
dragonBonesProjects/library/SoldierElf.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
1
dragonBonesProjects/library/SoldierFireGhost.json
Normal file
@@ -0,0 +1 @@
|
||||
{"imagePath":"Soldier_02_tex.png","width":128,"name":"Soldier_02","SubTexture":[{"x":53,"y":44,"width":23,"name":"biu","height":22},{"x":76,"y":68,"width":9,"name":"rightArm","height":14},{"y":35,"frameY":0,"height":32,"frameWidth":29,"frameX":-1,"frameHeight":32,"width":27,"name":"yinmoqe00","x":89},{"x":53,"y":1,"width":34,"name":"body","height":41},{"x":78,"y":44,"width":9,"name":"rightShoulder","height":13},{"y":50,"frameY":0,"height":18,"frameWidth":19,"frameX":0,"frameHeight":18,"width":19,"name":"rightFrontArm","x":23},{"x":23,"y":70,"width":14,"name":"rightHand","height":14},{"y":68,"frameY":0,"height":12,"frameWidth":12,"frameX":0,"frameHeight":12,"width":12,"name":"leftArm","x":62},{"x":1,"y":73,"width":13,"name":"leftShoulder","height":12},{"x":1,"y":50,"width":20,"name":"leftFrontArm","height":21},{"x":89,"y":1,"width":33,"name":"head","height":32},{"x":1,"y":1,"width":50,"name":"head2","height":47},{"x":44,"y":68,"width":16,"name":"leftHand","height":14},{"y":59,"frameY":-2,"height":4,"frameWidth":8,"frameX":-1,"frameHeight":8,"width":4,"name":"huomiao01","x":78}],"height":128}
|
BIN
dragonBonesProjects/library/SoldierFireGhost.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
1
dragonBonesProjects/library/SoldierWaterGhost.json
Normal file
@@ -0,0 +1 @@
|
||||
{"width":128,"SubTexture":[{"frameWidth":23,"y":50,"frameX":-2,"frameHeight":22,"frameY":-2,"width":19,"height":19,"name":"biu","x":1},{"width":9,"y":50,"height":14,"name":"rightArm","x":42},{"frameWidth":29,"y":34,"frameX":-6,"frameHeight":32,"frameY":0,"width":20,"height":32,"name":"yinmoqe00","x":88},{"frameWidth":34,"y":1,"frameX":0,"frameHeight":41,"frameY":0,"width":33,"height":39,"name":"body","x":53},{"width":9,"y":56,"height":13,"name":"rightShoulder","x":74},{"frameWidth":19,"y":50,"frameX":0,"frameHeight":18,"frameY":0,"width":18,"height":17,"name":"rightFrontArm","x":22},{"width":14,"y":50,"height":14,"name":"rightHand","x":110},{"width":12,"y":42,"height":12,"name":"leftArm","x":74},{"width":13,"y":66,"height":12,"name":"leftShoulder","x":110},{"frameWidth":20,"y":42,"frameX":-1,"frameHeight":21,"frameY":0,"width":19,"height":21,"name":"leftFrontArm","x":53},{"width":50,"y":1,"height":47,"name":"head2","x":1},{"frameWidth":33,"y":1,"frameX":-1,"frameHeight":32,"frameY":0,"width":32,"height":31,"name":"head","x":88},{"width":16,"y":34,"height":14,"name":"leftHand","x":110},{"frameWidth":8,"y":1,"frameX":-2,"frameHeight":8,"frameY":-3,"width":2,"height":2,"name":"huomiao01","x":122}],"height":128,"name":"SoldierWaterGhost","imagePath":"SoldierWaterGhost_tex.png"}
|
BIN
dragonBonesProjects/library/SoldierWaterGhost.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Bottom",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "783f1240-d608-40be-8108-3013ab53cfe6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "393e649b-addb-4f91-b687-438433026c8d"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "115ea7bb-d47f-4d3c-a52a-f46584346c3f",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "BottomLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "748c55f0-e761-40f6-b13b-e416b3d8a55c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "6164bac7-9882-43ce-b3d0-9d062d6d0b49"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "a1bf7c7c-b9f7-4b65-86e3-f86a9e798fb6",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "BottomRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "34cf9fbb-8def-4faf-a56e-123b4c45706c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "b6709dd6-6ba7-4222-af38-de79ac80ce8b"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "d5af527a-9f0c-4398-b2dd-84426be7bd32",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Left",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "02cd24e3-1c4a-46d7-85af-9034c9445ba7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "1f121837-a493-4a41-90e5-74ea560930ad"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "b60618d7-569d-4f13-bdeb-f20341fbadb6",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Right",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "a6ec6a1c-dde5-459d-84f9-7b2b8a163e7b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "b5d11244-f30a-4b0d-b67b-23648d253d44"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "0b3fb38e-9110-4191-9b72-6b64a224d049",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Top",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "8967d249-e9cf-4e44-85e8-6b9377129d9e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "492a57fb-6a5c-423a-bcfe-0695a7828881"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "1bc6de53-800b-4da3-ab8e-4a45e3aa4230",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TopLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "96187689-85df-46e8-b4db-410eae03c135"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "6b002583-7688-43d3-b3fa-102ae0046628"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "ee0d670c-893e-4e4d-96dd-5571db18ee97",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TopRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "ba89046f-8b70-4edb-9f61-534dff476325"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "bc1ef316-d6ad-4538-b223-a0fed8094609"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "596df84a-2e4e-4f1d-967c-a82649f564a8",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "attackedLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.3333333333333333,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "02cd24e3-1c4a-46d7-85af-9034c9445ba7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "8c522ad3-ee82-41a7-892e-05c05442e2e3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "1f121837-a493-4a41-90e5-74ea560930ad"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.25,
|
||||
"value": {
|
||||
"__uuid__": "1c0ec5ec-51cb-467d-b597-8e69ce580cfd"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "8acc4e9f-3c47-4b66-9a9d-d012709680f6",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "attackedRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.3333333333333333,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "a6ec6a1c-dde5-459d-84f9-7b2b8a163e7b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "d5ec0aaf-d4a9-4b2e-b9c1-bdc54b355b73"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "b5d11244-f30a-4b0d-b67b-23648d253d44"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.25,
|
||||
"value": {
|
||||
"__uuid__": "360dfc7d-4ed1-4fb9-8d2f-7533d05a4830"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "c7cda0cd-dbce-4722-abd2-aeca28263a21",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Bottom",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "c79694bc-ff6f-416b-9047-b82f41fe791a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "609c77a2-bdfe-4967-8de6-646532302c97"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "28194c48-ae3b-4197-8263-0d474ae8b9bc",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "BottomLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "07b6d385-3f51-48c1-8165-38756b3d84fa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "c627bf3b-0e97-4423-aeea-54c7511894d6"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "e1c45a36-2022-4b18-a2db-b5e2e0a120ed",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "BottomRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "d0327836-1910-4c6a-9291-c8bb044c54f5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "1d3e614a-bb2a-4b1d-87ca-0cddd6e03fff"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "126dff26-0ace-439d-89b5-b888aa52d159",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Left",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "c9528117-c878-41aa-ad5d-641fefcaa89f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "c0e5d042-8bc1-449b-9a2d-7844129c5188"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "95c2d541-8f99-446a-a7e0-094130ce6d41",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Right",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "1054cf4c-69a5-4834-8966-03bc613d4483"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "b88522bd-8b6b-44a1-9c84-5518ae7f5c2c"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "380f5fa0-f77f-434a-8f39-d545ee6823c5",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Top",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "9702ca76-66c8-4ea9-a976-45f86e15830a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "6390f1c3-b4cc-41df-acfb-645e8f90fb36"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "a306c6de-ccd8-492b-bfec-c6be0a4cbde2",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TopLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "a669112a-f263-443d-9757-60d0372e0fe8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "3ed70f56-3b60-4bda-9d2a-8d4b5ecb12f9"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "f496072b-51fd-4406-abbd-9885ac23f7a9",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TopRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "3d84f335-85c4-4dd0-a5d3-38f4da1e1611"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "6d36877f-dc27-4ebc-9407-14fbcf2314df"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "6405ad8b-3084-4b67-8c2e-9b4d34fa3d09",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "attackedLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.3333333333333333,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "c9528117-c878-41aa-ad5d-641fefcaa89f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "987c7dc0-e81f-4891-979d-0998794e6889"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "c0e5d042-8bc1-449b-9a2d-7844129c5188"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.25,
|
||||
"value": {
|
||||
"__uuid__": "9205c378-c50c-4303-af32-dbf9422375cf"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "af16cdcb-6e82-4be6-806d-9fc52ae99fff",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "attackedRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.3333333333333333,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "1054cf4c-69a5-4834-8966-03bc613d4483"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "8f3cf81e-1251-4013-b684-13f2830c7425"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "b88522bd-8b6b-44a1-9c84-5518ae7f5c2c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.25,
|
||||
"value": {
|
||||
"__uuid__": "69f1bd37-6628-4fd1-b0f2-08073d1edb29"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "02eba566-4d22-4fa7-99d7-f032f5845421",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "135f388e-7e75-4ece-b267-4e07835cba74",
|
||||
"uuid": "8f2f76c7-649c-414a-80be-b2daef4ed580",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
@@ -0,0 +1 @@
|
||||
{"imagePath":"SoldierWaterGhost_tex.png","width":64,"height":64,"name":"SoldierWaterGhost","SubTexture":[{"frameY":-1,"y":27,"frameWidth":12,"frameHeight":11,"width":10,"height":10,"name":"biu","frameX":-1,"x":1},{"width":5,"y":23,"height":7,"name":"rightArm","x":40},{"frameY":0,"y":19,"frameWidth":15,"frameHeight":16,"width":10,"height":16,"name":"yinmoqe00","frameX":-3,"x":47},{"frameY":0,"y":1,"frameWidth":17,"frameHeight":21,"width":17,"height":20,"name":"body","frameX":0,"x":28},{"width":5,"y":37,"height":7,"name":"rightShoulder","x":42},{"frameY":0,"y":27,"frameWidth":10,"frameHeight":9,"width":9,"height":9,"name":"rightFrontArm","frameX":0,"x":13},{"width":7,"y":38,"height":7,"name":"rightHand","x":13},{"width":6,"y":36,"height":6,"name":"leftArm","x":34},{"width":7,"y":39,"height":6,"name":"leftShoulder","x":1},{"frameY":0,"y":23,"frameWidth":10,"frameHeight":11,"width":10,"height":11,"name":"leftFrontArm","frameX":-1,"x":28},{"width":25,"y":1,"height":24,"name":"head2","x":1},{"frameY":0,"y":1,"frameWidth":17,"frameHeight":16,"width":16,"height":16,"name":"head","frameX":-1,"x":47},{"width":8,"y":36,"height":7,"name":"leftHand","x":24},{"frameY":-2,"y":32,"frameWidth":4,"frameHeight":4,"width":1,"height":1,"name":"huomiao01","frameX":-1,"x":42}]}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"uuid": "e9e703e9-3589-4713-b889-28b23406d220",
|
||||
"atlasJson": "{\"imagePath\":\"SoldierWaterGhost_tex.png\",\"width\":64,\"height\":64,\"name\":\"SoldierWaterGhost\",\"SubTexture\":[{\"frameY\":-1,\"y\":27,\"frameWidth\":12,\"frameHeight\":11,\"width\":10,\"height\":10,\"name\":\"biu\",\"frameX\":-1,\"x\":1},{\"width\":5,\"y\":23,\"height\":7,\"name\":\"rightArm\",\"x\":40},{\"frameY\":0,\"y\":19,\"frameWidth\":15,\"frameHeight\":16,\"width\":10,\"height\":16,\"name\":\"yinmoqe00\",\"frameX\":-3,\"x\":47},{\"frameY\":0,\"y\":1,\"frameWidth\":17,\"frameHeight\":21,\"width\":17,\"height\":20,\"name\":\"body\",\"frameX\":0,\"x\":28},{\"width\":5,\"y\":37,\"height\":7,\"name\":\"rightShoulder\",\"x\":42},{\"frameY\":0,\"y\":27,\"frameWidth\":10,\"frameHeight\":9,\"width\":9,\"height\":9,\"name\":\"rightFrontArm\",\"frameX\":0,\"x\":13},{\"width\":7,\"y\":38,\"height\":7,\"name\":\"rightHand\",\"x\":13},{\"width\":6,\"y\":36,\"height\":6,\"name\":\"leftArm\",\"x\":34},{\"width\":7,\"y\":39,\"height\":6,\"name\":\"leftShoulder\",\"x\":1},{\"frameY\":0,\"y\":23,\"frameWidth\":10,\"frameHeight\":11,\"width\":10,\"height\":11,\"name\":\"leftFrontArm\",\"frameX\":-1,\"x\":28},{\"width\":25,\"y\":1,\"height\":24,\"name\":\"head2\",\"x\":1},{\"frameY\":0,\"y\":1,\"frameWidth\":17,\"frameHeight\":16,\"width\":16,\"height\":16,\"name\":\"head\",\"frameX\":-1,\"x\":47},{\"width\":8,\"y\":36,\"height\":7,\"name\":\"leftHand\",\"x\":24},{\"frameY\":-2,\"y\":32,\"frameWidth\":4,\"frameHeight\":4,\"width\":1,\"height\":1,\"name\":\"huomiao01\",\"frameX\":-1,\"x\":42}]}",
|
||||
"texture": "def168c3-3f07-43f9-a460-36b397c70a57",
|
||||
"subMetas": {}
|
||||
}
|
After Width: | Height: | Size: 4.6 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "c30bd4d7-efdc-410c-8bdf-4a3dfc77bebd",
|
||||
"uuid": "def168c3-3f07-43f9-a460-36b397c70a57",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
@@ -9,21 +9,21 @@
|
||||
"packable": true,
|
||||
"platformSettings": {},
|
||||
"subMetas": {
|
||||
"Tile_W300_H300_S01": {
|
||||
"SoldierWaterGhost_tex": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "66b49304-7b5b-442c-92a5-d2b368abf659",
|
||||
"rawTextureUuid": "c30bd4d7-efdc-410c-8bdf-4a3dfc77bebd",
|
||||
"uuid": "52fb0606-bbea-433c-803b-bf5ce936a0df",
|
||||
"rawTextureUuid": "def168c3-3f07-43f9-a460-36b397c70a57",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 4,
|
||||
"offsetY": -24.5,
|
||||
"trimX": 97,
|
||||
"trimY": 85,
|
||||
"width": 114,
|
||||
"height": 179,
|
||||
"rawWidth": 300,
|
||||
"rawHeight": 300,
|
||||
"offsetX": 0,
|
||||
"offsetY": 9,
|
||||
"trimX": 1,
|
||||
"trimY": 1,
|
||||
"width": 62,
|
||||
"height": 44,
|
||||
"rawWidth": 64,
|
||||
"rawHeight": 64,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "0e243c83-a137-4880-9bfe-9e1b57adc453",
|
||||
"uuid": "2202f4f4-b792-4dea-8302-633315aded66",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
@@ -0,0 +1 @@
|
||||
{"width":128,"SubTexture":[{"frameWidth":34,"y":1,"frameHeight":45,"width":34,"frameX":0,"height":44,"name":"cape","frameY":0,"x":70},{"width":10,"y":107,"height":14,"name":"shouder_l","x":74},{"width":11,"y":107,"height":14,"name":"forearm_l","x":61},{"width":15,"y":93,"height":16,"name":"hand_l","x":1},{"width":30,"y":61,"height":30,"name":"weapon_hand_l","x":1},{"width":8,"y":88,"height":11,"name":"thigh_l","x":77},{"width":12,"y":93,"height":17,"name":"calf_l","x":18},{"width":20,"y":113,"height":8,"name":"foot_l","x":39},{"width":28,"y":61,"height":31,"name":"pelvis","x":33},{"width":8,"y":101,"height":11,"name":"thigh_r","x":86},{"width":12,"y":88,"height":17,"name":"calf_r","x":63},{"width":20,"y":113,"height":8,"name":"foot_r","x":17},{"width":13,"y":94,"height":12,"name":"shouder_r","x":45},{"width":67,"y":1,"height":58,"name":"chest","x":1},{"width":11,"y":94,"height":17,"name":"forearm_r","x":32},{"width":14,"y":111,"height":13,"name":"hand_r","x":1},{"frameWidth":36,"y":47,"frameHeight":39,"width":34,"frameX":-2,"height":39,"name":"we_bl_4_f_1","frameY":0,"x":70}],"height":128,"name":"SoldierElf","imagePath":"SoldierElf_tex.png"}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"uuid": "24d7bb8f-577c-4e5d-b730-56613ca8685d",
|
||||
"atlasJson": "{\"width\":128,\"SubTexture\":[{\"frameWidth\":34,\"y\":1,\"frameHeight\":45,\"width\":34,\"frameX\":0,\"height\":44,\"name\":\"cape\",\"frameY\":0,\"x\":70},{\"width\":10,\"y\":107,\"height\":14,\"name\":\"shouder_l\",\"x\":74},{\"width\":11,\"y\":107,\"height\":14,\"name\":\"forearm_l\",\"x\":61},{\"width\":15,\"y\":93,\"height\":16,\"name\":\"hand_l\",\"x\":1},{\"width\":30,\"y\":61,\"height\":30,\"name\":\"weapon_hand_l\",\"x\":1},{\"width\":8,\"y\":88,\"height\":11,\"name\":\"thigh_l\",\"x\":77},{\"width\":12,\"y\":93,\"height\":17,\"name\":\"calf_l\",\"x\":18},{\"width\":20,\"y\":113,\"height\":8,\"name\":\"foot_l\",\"x\":39},{\"width\":28,\"y\":61,\"height\":31,\"name\":\"pelvis\",\"x\":33},{\"width\":8,\"y\":101,\"height\":11,\"name\":\"thigh_r\",\"x\":86},{\"width\":12,\"y\":88,\"height\":17,\"name\":\"calf_r\",\"x\":63},{\"width\":20,\"y\":113,\"height\":8,\"name\":\"foot_r\",\"x\":17},{\"width\":13,\"y\":94,\"height\":12,\"name\":\"shouder_r\",\"x\":45},{\"width\":67,\"y\":1,\"height\":58,\"name\":\"chest\",\"x\":1},{\"width\":11,\"y\":94,\"height\":17,\"name\":\"forearm_r\",\"x\":32},{\"width\":14,\"y\":111,\"height\":13,\"name\":\"hand_r\",\"x\":1},{\"frameWidth\":36,\"y\":47,\"frameHeight\":39,\"width\":34,\"frameX\":-2,\"height\":39,\"name\":\"we_bl_4_f_1\",\"frameY\":0,\"x\":70}],\"height\":128,\"name\":\"SoldierElf\",\"imagePath\":\"SoldierElf_tex.png\"}",
|
||||
"texture": "050fb016-1a1f-4341-8367-283bfeddc4a8",
|
||||
"subMetas": {}
|
||||
}
|
After Width: | Height: | Size: 7.1 KiB |
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "050fb016-1a1f-4341-8367-283bfeddc4a8",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
"premultiplyAlpha": false,
|
||||
"genMipmaps": false,
|
||||
"packable": true,
|
||||
"platformSettings": {},
|
||||
"subMetas": {
|
||||
"SoldierElf_tex": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "c62e1779-f92b-40d3-bf4f-7ab747e33d6e",
|
||||
"rawTextureUuid": "050fb016-1a1f-4341-8367-283bfeddc4a8",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": -11.5,
|
||||
"offsetY": 1.5,
|
||||
"trimX": 1,
|
||||
"trimY": 1,
|
||||
"width": 103,
|
||||
"height": 123,
|
||||
"rawWidth": 128,
|
||||
"rawHeight": 128,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"subMetas": {}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "51c54820-d753-4be8-a855-5760eed8f7ef",
|
||||
"uuid": "f1176719-d1d6-4af5-89c6-ddff16ab85fd",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
@@ -0,0 +1 @@
|
||||
{"imagePath":"SoldierFireGhost_tex.png","width":64,"height":64,"name":"SoldierFireGhost","SubTexture":[{"frameY":0,"y":42,"frameWidth":12,"frameHeight":11,"width":11,"height":11,"name":"biu","frameX":-1,"x":16},{"width":5,"y":42,"height":7,"name":"rightArm","x":29},{"frameY":0,"y":27,"frameWidth":15,"frameHeight":16,"width":13,"height":16,"name":"yinmoqe00","frameX":-1,"x":1},{"width":17,"y":1,"height":21,"name":"body","x":28},{"width":5,"y":42,"height":7,"name":"rightShoulder","x":36},{"width":10,"y":45,"height":9,"name":"rightFrontArm","x":1},{"width":7,"y":56,"height":7,"name":"rightHand","x":1},{"width":6,"y":55,"height":6,"name":"leftArm","x":32},{"width":7,"y":55,"height":6,"name":"leftShoulder","x":23},{"width":10,"y":27,"height":11,"name":"leftFrontArm","x":16},{"width":25,"y":1,"height":24,"name":"head2","x":1},{"width":17,"y":24,"height":16,"name":"head","x":28},{"width":8,"y":55,"height":7,"name":"leftHand","x":13},{"frameY":-1,"y":51,"frameWidth":4,"frameHeight":4,"width":2,"height":2,"name":"huomiao01","frameX":-1,"x":29}]}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"uuid": "4a9187d5-a9ad-4464-a03c-d2f3cc277051",
|
||||
"atlasJson": "{\"imagePath\":\"SoldierFireGhost_tex.png\",\"width\":64,\"height\":64,\"name\":\"SoldierFireGhost\",\"SubTexture\":[{\"frameY\":0,\"y\":42,\"frameWidth\":12,\"frameHeight\":11,\"width\":11,\"height\":11,\"name\":\"biu\",\"frameX\":-1,\"x\":16},{\"width\":5,\"y\":42,\"height\":7,\"name\":\"rightArm\",\"x\":29},{\"frameY\":0,\"y\":27,\"frameWidth\":15,\"frameHeight\":16,\"width\":13,\"height\":16,\"name\":\"yinmoqe00\",\"frameX\":-1,\"x\":1},{\"width\":17,\"y\":1,\"height\":21,\"name\":\"body\",\"x\":28},{\"width\":5,\"y\":42,\"height\":7,\"name\":\"rightShoulder\",\"x\":36},{\"width\":10,\"y\":45,\"height\":9,\"name\":\"rightFrontArm\",\"x\":1},{\"width\":7,\"y\":56,\"height\":7,\"name\":\"rightHand\",\"x\":1},{\"width\":6,\"y\":55,\"height\":6,\"name\":\"leftArm\",\"x\":32},{\"width\":7,\"y\":55,\"height\":6,\"name\":\"leftShoulder\",\"x\":23},{\"width\":10,\"y\":27,\"height\":11,\"name\":\"leftFrontArm\",\"x\":16},{\"width\":25,\"y\":1,\"height\":24,\"name\":\"head2\",\"x\":1},{\"width\":17,\"y\":24,\"height\":16,\"name\":\"head\",\"x\":28},{\"width\":8,\"y\":55,\"height\":7,\"name\":\"leftHand\",\"x\":13},{\"frameY\":-1,\"y\":51,\"frameWidth\":4,\"frameHeight\":4,\"width\":2,\"height\":2,\"name\":\"huomiao01\",\"frameX\":-1,\"x\":29}]}",
|
||||
"texture": "700d963b-2192-4219-a066-8be5b3db7453",
|
||||
"subMetas": {}
|
||||
}
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "700d963b-2192-4219-a066-8be5b3db7453",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
"premultiplyAlpha": false,
|
||||
"genMipmaps": false,
|
||||
"packable": true,
|
||||
"platformSettings": {},
|
||||
"subMetas": {
|
||||
"SoldierFireGhost_tex": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "8ef8a6b3-0bac-4cf1-bba0-ab090f4d9e52",
|
||||
"rawTextureUuid": "700d963b-2192-4219-a066-8be5b3db7453",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": -9,
|
||||
"offsetY": 0,
|
||||
"trimX": 1,
|
||||
"trimY": 1,
|
||||
"width": 44,
|
||||
"height": 62,
|
||||
"rawWidth": 64,
|
||||
"rawHeight": 64,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"subMetas": {}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "3b7d864f-c9fd-4030-a6dc-9814ee12fec1",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Atk1",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.5833333333333334,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "7fedc57f-6998-45fc-899d-ea5edd41ab13"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.016666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "d55c2f3c-9110-4627-b8b2-0f9395f0d145"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.03333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "1228879d-d28e-48e4-a3ce-5ceda0d1831f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.05,
|
||||
"value": {
|
||||
"__uuid__": "e88dd5c4-cc5d-46e0-88de-e382e2bcadd7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.06666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "df069f5c-7fc0-4731-bb7f-9d2032498e4c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "4815763d-64e1-4b15-b795-38900861c651"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.1,
|
||||
"value": {
|
||||
"__uuid__": "0dca4f06-bf25-4e7f-ac3a-1687e284f5d6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.11666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "de8db3c9-affd-45ef-a536-e2d28ebc8094"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.13333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "baaafb8b-9c1a-45ea-ba80-eb8048b61b57"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.15,
|
||||
"value": {
|
||||
"__uuid__": "9ffa7db6-1aec-4a1e-a8a9-118f2a6e50dc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "f2f296ad-0e19-4b00-b061-8c9edff98d0d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.18333333333333332,
|
||||
"value": {
|
||||
"__uuid__": "3e546607-d27f-40fa-9967-771c55a12590"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.2,
|
||||
"value": {
|
||||
"__uuid__": "fece0129-e8ae-45be-b963-e2b821add0d3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.21666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "f5f48bec-3d2a-49de-9416-26cc75d34e32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.23333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "b083cfc9-a439-4600-b336-b50ca08b68c4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.25,
|
||||
"value": {
|
||||
"__uuid__": "d04003f5-16c1-4510-898b-9148b76eb958"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.26666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "2159f038-bffa-480c-a2bd-c305868f2fd9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.2833333333333333,
|
||||
"value": {
|
||||
"__uuid__": "1d3de292-7dd4-4e28-b1d2-23fc38318390"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3,
|
||||
"value": {
|
||||
"__uuid__": "3031ca7c-e1f7-4d14-b29e-5a7102cab245"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.31666666666666665,
|
||||
"value": {
|
||||
"__uuid__": "987e9d14-b6fc-46c7-93ed-8914e42bfa8b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "327db66e-2136-4d52-9727-399d60715a86"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.35,
|
||||
"value": {
|
||||
"__uuid__": "82ab2dcd-22e9-490f-96c4-4786018c91d0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.36666666666666664,
|
||||
"value": {
|
||||
"__uuid__": "36812959-85a6-40fb-9a38-1b4d871eba92"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.38333333333333336,
|
||||
"value": {
|
||||
"__uuid__": "2941d74c-7b9c-43dc-a5c4-45952220d9a2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.4,
|
||||
"value": {
|
||||
"__uuid__": "4aed2032-25d5-42fd-983a-4473e2985a99"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.4166666666666667,
|
||||
"value": {
|
||||
"__uuid__": "3db216c1-3362-4404-8db6-11615bfa6e64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.43333333333333335,
|
||||
"value": {
|
||||
"__uuid__": "2cf0cb17-cbb0-4d64-9c91-83639a363158"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.45,
|
||||
"value": {
|
||||
"__uuid__": "9c057e2c-1dc4-4c6c-adb7-85bf691cefb5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.4666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "49c07a7f-2ace-4e2b-ba4c-724aad12ec5c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.48333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "cec3c067-c958-4988-b113-2f10d7f4f5ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5,
|
||||
"value": {
|
||||
"__uuid__": "ad57f789-a25a-411c-b130-62a8ab16177f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5166666666666667,
|
||||
"value": {
|
||||
"__uuid__": "3c2a21a5-7c85-48f3-95ff-0d7a32e5e852"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "fe15eece-07a5-4d15-927b-af980aea7693"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.55,
|
||||
"value": {
|
||||
"__uuid__": "30ac103a-0f2b-45db-9442-461479beeb0d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "76272ec6-0721-4496-941b-5cb6a52b2c35"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "c738236a-0702-45f8-aa38-99457b051997",
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Atked1",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.31666666666666665,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "6fd7cfcb-95b2-4197-a065-6bc48365f855"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.016666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "39aaeff6-3116-4e12-8ec4-9362a8a2fea2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.03333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "fb4e42e6-0fae-48d4-a600-217e01d43e57"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.05,
|
||||
"value": {
|
||||
"__uuid__": "2af606d7-4b3d-4355-95d1-a3ab673d2a2e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.06666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "be18e65b-346c-4efb-84cb-7f317fcaf8ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "d269af72-8b89-420c-ba9e-6892cda06e80"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.1,
|
||||
"value": {
|
||||
"__uuid__": "30539c9d-6dbb-4409-8562-6c24b12010c2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.11666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "96b655f9-9a90-4cb1-86ab-0be881ad8983"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.13333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "a86f8107-3d8d-426e-9a17-c856c1ab292a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.15,
|
||||
"value": {
|
||||
"__uuid__": "d7f99f14-9257-426a-9e90-a948e7ca8d23"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "809dcbcf-9edd-4b8b-8bc8-42394ce0a9c2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.18333333333333332,
|
||||
"value": {
|
||||
"__uuid__": "f3e74927-2eea-4306-ba0a-c89972ca88f1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.2,
|
||||
"value": {
|
||||
"__uuid__": "af7a23f6-9b5c-4fe8-aa74-741f18500866"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.21666666666666667,
|
||||
"value": {
|
||||
"__uuid__": "4cc6ecdb-3741-4a2e-87a0-a93739a38d37"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.23333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "f809b6d3-6f5b-4cf4-b148-5cf7fdf407a5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.25,
|
||||
"value": {
|
||||
"__uuid__": "b1c9e526-fe26-42a8-9257-7e5549847273"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.26666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "db62c862-7553-4f99-b758-8c4a4aec438a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.2833333333333333,
|
||||
"value": {
|
||||
"__uuid__": "55f68905-bff7-48ea-b497-5077f49b2aca"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3,
|
||||
"value": {
|
||||
"__uuid__": "b01f45f9-c394-4706-aae1-d1d26a84f48a"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|