Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8038b393e0 | ||
|
4e0f7b52d4 | ||
|
486c46f608 | ||
|
6d075877ec | ||
|
fe826b393b | ||
|
c69aa25353 | ||
|
0f4d067c06 | ||
|
cff31d295c | ||
|
150e30db2a | ||
|
bc8989a0e6 | ||
|
1959a7fd9a | ||
|
3baaf1d52c | ||
|
62f10e0877 | ||
|
c3c7854e92 | ||
|
cb794d70c7 | ||
|
0047259e9f | ||
|
232d8ad148 | ||
|
d49e7830d4 | ||
|
1122f4d71c | ||
|
f2c8d4cd65 | ||
|
4e7f9e63ac | ||
|
e762d257a6 | ||
|
286944b88c | ||
|
05dc593d2c | ||
|
5f9aaddc9c | ||
|
e224aaf680 | ||
|
9c07b43157 | ||
|
3203ea9f1e | ||
|
d90c4ead91 | ||
|
1e5d7d1d06 | ||
|
a6731dc7d6 | ||
|
1004fd45db | ||
|
09b12c5b16 | ||
|
9d9bea21ef | ||
|
54d6e52498 | ||
|
4d1de44ee5 | ||
|
f3a576ba13 | ||
|
2264c0d362 | ||
|
cd83539197 | ||
|
a2a8be9068 | ||
|
527cc94242 | ||
|
266335b7c6 | ||
|
14fb8e94b2 | ||
|
ff092a40ed | ||
|
80dc05a92b | ||
|
2dfd6083c5 | ||
|
50273c981b | ||
|
114e6b0501 | ||
|
cccbeb1c29 | ||
|
1cc0eed39e | ||
|
85c94a9e5d |
43
ConcerningEdgeCases.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# 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
|
||||
- player#2: renderFrameId = 240
|
||||
- player#3: renderFrameId = 239
|
||||
- player#4: renderFrameId = 242
|
||||
|
||||
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)`.
|
||||
|
||||
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.
|
||||
|
||||
# Start up frames
|
||||
renderFrameId | generatedInputFrameId | toApplyInputFrameId
|
||||
-------------------|----------------------------|----------------------
|
||||
0, 1, 2, 3 | 0, _EMP_, _EMP_, _EMP_ | 0
|
||||
4, 5, 6, 7 | 1, _EMP_, _EMP_, _EMP_ | 0
|
||||
8, 9, 10, 11 | 2, _EMP_, _EMP_, _EMP_ | 1
|
||||
12, 13, 14, 15 | 3, _EMP_, _EMP_, _EMP_ | 2
|
||||
|
||||
It should be reasonable to assume that inputFrameId=0 is always of all-empty content, because human has no chance of clicking at the very first render frame.
|
||||
|
||||
# Alignment of the current setup
|
||||
The following setup is chosen deliberately for some "%4" number coincidence.
|
||||
- NstDelayFrames = 2
|
||||
- InputDelayFrames = 4
|
||||
- InputScaleFrames = 2
|
||||
|
||||
If "InputDelayFrames" is changed, the impact would be as follows, kindly note that "372%4 == 0".
|
||||
|
||||
### pR.InputDelayFrames = 4
|
||||
renderFrameId | toApplyInputFrameId
|
||||
--------------------------|----------------------------------------------------
|
||||
368, 369, 370, 371 | 91
|
||||
372, 373, 374, 375 | 92
|
||||
|
||||
### pR.InputDelayFrames = 5
|
||||
renderFrameId | toApplyInputFrameId
|
||||
--------------------------|----------------------------------------------------
|
||||
..., ..., ..., 368 | 90
|
||||
369, 370, 371, 372 | 91
|
||||
373, 374, 375, ... | 92
|
83
README.md
@@ -1,53 +1,76 @@
|
||||
# 0. Preface
|
||||
If you'd like to play with the backend code seriously, please read the detailed explanation of its important "lifecycle events" in [this note](https://app.yinxiang.com/fx/5c575124-01db-419b-9c02-ec81f78c6ddc).
|
||||
# Preface
|
||||
|
||||
There could be some left over wechat-game related code pieces, but they're neither meant to work nor supported anymore.
|
||||
This project is a demo for a websocket-based input synchronization method inspired by [GGPO](https://www.ggpo.net/).
|
||||

|
||||
|
||||
# 1. Database Server
|
||||
Please checkout [this demo video](https://pan.baidu.com/s/1aM6e8IWaJszFCYAsRjt19g?pwd=z02c) to see whether the source codes are doing what you expect for synchronization.
|
||||
|
||||
The database product to be used for this project is MySQL 5.7.
|
||||
The video mainly shows the following feature (yet I'm not surprised if they're not obvious): when a player didn't have its input arrived at the backend in time (e.g. due to local lag, network delay or reconnection), backend forces confirmation of a prediction of its own and sends the confirmed input together w/ a reference render frame to that player.
|
||||
|
||||
We use [skeema](https://github.com/skeema/skeema) for schematic synchronization under `<proj-root>/database/skeema-repo-root/` which intentionally doesn't contain a `.skeema` file. Please read [this tutorial](https://shimo.im/doc/wQ0LvB0rlZcbHF5V) for more information.
|
||||
# 1. Building & running
|
||||
|
||||
You can use [this node module (still under development)](https://github.com/genxium/node-mysqldiff-bridge) instead under `Windows10`, other versions of Windows are not yet tested for compatibility.
|
||||
## 1.1 Tools to install
|
||||
### Backend
|
||||
- [Command Line Tools for Xcode](https://developer.apple.com/download/all/?q=command%20line%20tools) (on OSX) or [TDM-GCC](https://jmeubank.github.io/tdm-gcc/download/) (on Windows) (a `make` executable mandatory)
|
||||
- [Golang1.19.1](https://golang.org/dl/) (mandatory, in China please try a mirror site like [that of ustc](https://mirrors.ustc.edu.cn/golang/))
|
||||
- [MySQL 5.7](https://dev.mysql.com/downloads/windows/installer/5.7.html) (mandatory, for OSX not all versions of 5.7 can be found thus 5.7.24 is recommended)
|
||||
- [Redis 3.0.503 or above](https://redis.io/download/) (mandatory)
|
||||
- [skeema](https://www.skeema.io/) (optional, only for convenient MySQL schema provisioning)
|
||||
- [protobuf CLI](https://developers.google.com/protocol-buffers/docs/downloads) (optional, only for development)
|
||||
|
||||
The following command(s)
|
||||
### Frontend
|
||||
- [CocosCreator v2.2.1](https://www.cocos.com/en/cocos-creator-2-2-1-released-with-performance-improvements) (mandatory, **ONLY AVAILABLE on Windows or OSX and should be exactly this version**, DON'T use any other version because CocosCreator is well-known for new versions not being backward incompatible)
|
||||
- [protojs](https://www.npmjs.com/package/protojs) (optional, only for development)
|
||||
|
||||
## 1.2 Provisioning
|
||||
### Backend/Database
|
||||
It's strongly recommended that `skeema` is used for provisioning [the required schema](https://github.com/genxium/DelayNoMore/tree/main/database/skeema-repo-root) in MySQL instance. When using `skeema` the steps are as follows.
|
||||
```
|
||||
### Optional.
|
||||
### Mandatory after an initial clone
|
||||
user@proj-root/database/skeema-repo-root> cp .skeema.template .skeema
|
||||
|
||||
###
|
||||
user@proj-root/database/skeema-repo-root> skeema diff
|
||||
### Mandatory
|
||||
user@proj-root/database/skeema-repo-root> skeema push
|
||||
```
|
||||
is recommended to be used for checking difference from your "live MySQL server" to the latest expected schema tracked in git.
|
||||
|
||||
# 2. Building & running
|
||||
On `Windows 10/11`, you can compile `skeema` from source and config the host to be `127.0.0.1` instead of `localhost` to use it, i.e. circumventing the pitfall for MySQL unix socket connection on Windows.
|
||||
|
||||
## 2.1 Golang1.11
|
||||
See https://github.com/genxium/Go111ModulePrac for details.
|
||||
### Backend/Golang
|
||||
```
|
||||
user@proj-root/battle_srv/configs> cp -r ./configs.template ./configs
|
||||
```
|
||||
|
||||
## 2.2 MySQL
|
||||
On a product machine, you can install and manage `MySQL` server by [these scripts](https://github.com/genxium/Ubuntu14InitScripts/tree/master/database/mysql).
|
||||
### Frontend
|
||||
```
|
||||
user@proj-root/frontend/assets/plugin_scripts> cp ./conf.js.template ./conf.js
|
||||
```
|
||||
|
||||
## 2.3 Required Config Files
|
||||
## 1.2 Actual building & running
|
||||
### Backend
|
||||
```
|
||||
### The following command runs mysql-server in foreground, it's almost NEVER run in such a way, please find a proper way to run it for yourself
|
||||
user@anywhere> mysqld
|
||||
|
||||
### 2.3.1 Backend
|
||||
- It needs `<proj-root>/battle_srv/configs/*` which is generated by `cd <proj-root>/battle_srv && cp -r ./configs.template ./configs` and necessary customization.
|
||||
### The following command runs redis-server in foreground, it's OK to put it in background
|
||||
user@anywhere> redis-server
|
||||
|
||||
### 2.3.2 Frontend
|
||||
- It needs CocosCreator v2.2.1 to build.
|
||||
- A required "CocosCreator plugin `i18n`" is already enclosed in the project, if you have a globally installed "CocosCreator plugin `i18n`"(often located at `$HOME/.CocosCreator/packages/`) they should be OK to co-exist.
|
||||
- It needs `<proj-root>/frontend/assets/plugin_scripts/conf.js` which is generated by `cd <proj-root>/frontend/assets/plugin_scripts && cp conf.js.template conf.js`.
|
||||
### on Windows using TDM-GCC: mingw32-make run-test
|
||||
user@proj-root/battle_srv> make run-test
|
||||
```
|
||||
|
||||
## 2.4 Troubleshooting
|
||||
### Frontend
|
||||
The easy way is to try out 2 players with test accounts on a same machine.
|
||||
- Open CocosCreator v2.2.1 (mandatory, it serves the web content of the following steps)
|
||||
- Open one browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `add`on the username box and click to request a captcha, this is a test account so a captcha would be returned by the backend and filled automatically (as shown in the figure below), then click and click to proceed to a matching scene.
|
||||
- Open another browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `bdd`on the username box and click to request a captcha, this is another test account so a captcha would be returned by the backend and filled automatically, then click and click to proceed, when matched a `battle`(but no competition rule yet) would start.
|
||||
- Try out the onscreen virtual joysticks to move the cars and see if their movements are in-sync.
|
||||

|
||||
|
||||
### 2.4.1 Redis snapshot writing failure
|
||||
## 2 Troubleshooting
|
||||
|
||||
### 2.1 Redis snapshot writing failure
|
||||
```
|
||||
ErrFatal {"err": "MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error."}
|
||||
```
|
||||
|
||||
Just restart your `redis-server` process.
|
||||
|
||||
# 3. Git configs cautions
|
||||
|
||||
Please make sure that you've set `ignorecase = false` in your `[core] section of <proj-root>/.git/config`.
|
||||
|
@@ -2,10 +2,10 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
. "dnmshared"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
. "server/common"
|
||||
)
|
||||
|
||||
func RequestLogger() gin.HandlerFunc {
|
||||
|
@@ -16,6 +16,8 @@ import (
|
||||
"server/models"
|
||||
"server/storage"
|
||||
"strconv"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
var Player = playerController{}
|
||||
|
@@ -1,16 +1,15 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// 隐式导入
|
||||
var Conf *config
|
||||
|
||||
const (
|
||||
@@ -72,11 +71,15 @@ func MustParseConfig() {
|
||||
BotServer: new(botServerConf),
|
||||
}
|
||||
execPath, err := os.Executable()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
Logger.Debug("os.GetWd", zap.String("pwd", pwd))
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
appRoot := pwd
|
||||
confDir := filepath.Join(appRoot, "configs")
|
||||
@@ -129,22 +132,21 @@ func loadJSON(fp string, v interface{}) {
|
||||
fp = filepath.Join(Conf.General.ConfDir, fp)
|
||||
}
|
||||
_, err := os.Stat(fp)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fd, err := os.Open(fp)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
defer fd.Close()
|
||||
Logger.Info("Opened json file successfully.", zap.String("fp", fp))
|
||||
err = json.NewDecoder(fd).Decode(v)
|
||||
ErrFatal(err)
|
||||
Logger.Info("Loaded json file successfully.", zap.String("fp", fp))
|
||||
}
|
||||
|
||||
// Please only use this auxiliary function before server is fully started up, but not afterwards (启动过程可以使用,运行时不准使用).
|
||||
func ErrFatal(err error) {
|
||||
if err != nil {
|
||||
Logger.Fatal("ErrFatal", zap.NamedError("err", err))
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
Logger.Info("Loaded json file successfully.", zap.String("fp", fp))
|
||||
}
|
||||
|
||||
func isNotExist(p string) bool {
|
||||
|
@@ -5,9 +5,10 @@ import (
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"go.uber.org/zap"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
// 隐式导入
|
||||
var Constants *constants
|
||||
|
||||
func MustParseConstants() {
|
||||
@@ -24,13 +25,11 @@ func MustParseConstants() {
|
||||
if !isNotExist(fp) {
|
||||
testConstants := new(constants)
|
||||
loadJSON(fp, testConstants)
|
||||
//Logger.Debug(spew.Sdump(Constants))
|
||||
//Logger.Debug(spew.Sdump(testConstants))
|
||||
err := mergo.Merge(testConstants, Constants)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
Constants = testConstants
|
||||
//Logger.Debug("mergo.Merge", zap.Error(err))
|
||||
//Logger.Debug(spew.Sdump(testConstants))
|
||||
}
|
||||
}
|
||||
constantsPost()
|
||||
|
@@ -3,6 +3,7 @@ package utils
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
. "dnmshared"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
@@ -94,7 +95,7 @@ func (w *wechat) GetJsConfig(uri string) (config *JsConfig, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
//TODO add cache, getTicket 获取jsapi_ticket
|
||||
// TODO add cache, getTicket 获取jsapi_ticket
|
||||
func (w *wechat) getTicket() (ticketStr string, err error) {
|
||||
var ticket resTicket
|
||||
ticket, err = w.getTicketFromServer()
|
||||
@@ -131,7 +132,7 @@ func (w *wechat) GetOauth2Basic(authcode string) (result resAccessToken, err err
|
||||
return
|
||||
}
|
||||
|
||||
//UserInfo 用户授权获取到用户信息
|
||||
// UserInfo 用户授权获取到用户信息
|
||||
type UserInfo struct {
|
||||
CommonError
|
||||
OpenID string `json:"openid"`
|
||||
@@ -164,7 +165,7 @@ func (w *wechat) GetMoreInfo(accessToken string, openId string) (result UserInfo
|
||||
return
|
||||
}
|
||||
|
||||
//HTTPGet get 请求
|
||||
// HTTPGet get 请求
|
||||
func get(uri string) ([]byte, error) {
|
||||
response, err := http.Get(uri)
|
||||
if err != nil {
|
||||
@@ -182,7 +183,7 @@ func get(uri string) ([]byte, error) {
|
||||
return body, err
|
||||
}
|
||||
|
||||
//PostJSON post json 数据请求
|
||||
// PostJSON post json 数据请求
|
||||
func post(uri string, obj interface{}) ([]byte, error) {
|
||||
jsonData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
@@ -206,7 +207,7 @@ func post(uri string, obj interface{}) ([]byte, error) {
|
||||
return ioutil.ReadAll(response.Body)
|
||||
}
|
||||
|
||||
//Signature sha1签名
|
||||
// Signature sha1签名
|
||||
func signature(params ...string) string {
|
||||
sort.Strings(params)
|
||||
h := sha1.New()
|
||||
@@ -216,7 +217,7 @@ func signature(params ...string) string {
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
//RandomStr 随机生成字符串
|
||||
// RandomStr 随机生成字符串
|
||||
func randomStr(length int) string {
|
||||
str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
bytes := []byte(str)
|
||||
@@ -228,7 +229,7 @@ func randomStr(length int) string {
|
||||
return string(result)
|
||||
}
|
||||
|
||||
//getTicketFromServer 强制从服务器中获取ticket
|
||||
// getTicketFromServer 强制从服务器中获取ticket
|
||||
func (w *wechat) getTicketFromServer() (ticket resTicket, err error) {
|
||||
var accessToken string
|
||||
accessToken, err = w.getAccessTokenFromServer()
|
||||
@@ -256,7 +257,7 @@ func (w *wechat) getTicketFromServer() (ticket resTicket, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
//GetAccessTokenFromServer 强制从微信服务器获取token
|
||||
// GetAccessTokenFromServer 强制从微信服务器获取token
|
||||
func (w *wechat) getAccessTokenFromServer() (accessToken string, err error) {
|
||||
AccessTokenURL := w.config.ApiProtocol + "://" + w.config.ApiGateway + "/cgi-bin/token"
|
||||
url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", AccessTokenURL, w.config.AppID, w.config.AppSecret)
|
||||
|
@@ -11,7 +11,6 @@ var (
|
||||
RE_CHINA_PHONE_NUM = regexp.MustCompile(`^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$`)
|
||||
)
|
||||
|
||||
// 隐式导入
|
||||
var ConstVals = &struct {
|
||||
Player struct {
|
||||
CaptchaExpire time.Duration
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package env_tools
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
@@ -15,7 +16,9 @@ func LoadPreConf() {
|
||||
Logger.Info(`Merging PreConfSQLite data into MySQL`,
|
||||
zap.String("PreConfSQLitePath", Conf.General.PreConfSQLitePath))
|
||||
db, err := sqlx.Connect("sqlite3", Conf.General.PreConfSQLitePath)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
loadPreConfToMysql(db)
|
||||
@@ -39,7 +42,9 @@ func loadPreConfToMysql(db *sqlx.DB) {
|
||||
func loadSqlite(db *sqlx.DB, tbs []string) {
|
||||
for _, v := range tbs {
|
||||
result, err := storage.MySQLManagerIns.Exec("truncate " + v)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
Logger.Info("truncate", zap.Any("truncate "+v, result))
|
||||
query, args, err := sq.Select("*").From(v).ToSql()
|
||||
if err != nil {
|
||||
@@ -66,23 +71,29 @@ func createMysqlData(rows *sqlx.Rows, v string) {
|
||||
}
|
||||
}
|
||||
|
||||
//加上tableName参数, 用于pre_conf_data.sqlite里bot_player表的复用 --kobako
|
||||
// 加上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)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
names := make([]string, len(ls), len(ls))
|
||||
for i, v := range ls {
|
||||
names[i] = v.Name
|
||||
}
|
||||
sql := "SELECT name FROM `player` WHERE name in (?)"
|
||||
query, args, err := sqlx.In(sql, names)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
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...)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, botPlayer := range ls {
|
||||
var flag bool
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package env_tools
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
"server/models"
|
||||
@@ -15,7 +16,9 @@ func MergeTestPlayerAccounts() {
|
||||
fp := Conf.General.TestEnvSQLitePath
|
||||
Logger.Info(`Initializing TestPlayerAccounts in runtime MySQLServer from SQLite file:`, zap.String("fp", fp))
|
||||
db, err := sqlx.Connect("sqlite3", fp)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
defer db.Close()
|
||||
maybeCreateNewPlayer(db, "test_player")
|
||||
}
|
||||
@@ -29,31 +32,35 @@ type dbTestPlayer struct {
|
||||
func maybeCreateNewPlayer(db *sqlx.DB, tableName string) {
|
||||
var ls []*dbTestPlayer
|
||||
err := db.Select(&ls, "SELECT name, magic_phone_country_code, magic_phone_num FROM "+tableName)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
names := make([]string, len(ls), len(ls))
|
||||
for i, v := range ls {
|
||||
names[i] = v.Name
|
||||
}
|
||||
sql := "SELECT name FROM `player` WHERE name in (?)"
|
||||
query, args, err := sqlx.In(sql, names)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
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...)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, testPlayer := range ls {
|
||||
var flag bool
|
||||
for _, v := range existPlayers {
|
||||
if testPlayer.Name == v.Name {
|
||||
// 已有数据,合并处理
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !flag {
|
||||
// 找不到,新增
|
||||
Logger.Debug("create", zap.Any(tableName, testPlayer))
|
||||
err := createNewPlayer(testPlayer)
|
||||
if err != nil {
|
||||
|
@@ -1,37 +1,51 @@
|
||||
module server
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/ByteArena/box2d v1.0.2
|
||||
github.com/ChimeraCoder/gojson v1.0.0 // indirect
|
||||
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/fatih/color v1.7.0 // indirect
|
||||
github.com/gin-contrib/cors v0.0.0-20180514151808-6f0a820f94be
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
|
||||
github.com/gin-gonic/gin v1.3.0
|
||||
github.com/githubnemo/CompileDaemon v1.0.0 // indirect
|
||||
github.com/go-redis/redis v6.13.2+incompatible
|
||||
github.com/go-sql-driver/mysql v1.4.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/gorilla/websocket v1.2.0
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186
|
||||
github.com/howeyc/fsnotify v0.9.0 // indirect
|
||||
github.com/imdario/mergo v0.3.6
|
||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e
|
||||
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
|
||||
github.com/solarlune/resolv v0.5.1
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713
|
||||
go.uber.org/zap v1.9.1
|
||||
google.golang.org/protobuf v1.28.1
|
||||
|
||||
dnmshared v0.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ChimeraCoder/gojson v1.0.0 // indirect
|
||||
github.com/fatih/color v1.7.0 // indirect
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
|
||||
github.com/githubnemo/CompileDaemon v1.0.0 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/howeyc/fsnotify v0.9.0 // indirect
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e
|
||||
github.com/mattn/go-colorable v0.0.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.3 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.9.0
|
||||
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||
github.com/ugorji/go v1.1.1 // indirect
|
||||
go.uber.org/atomic v1.3.2 // indirect
|
||||
go.uber.org/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.9.1
|
||||
google.golang.org/protobuf v1.28.1
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
dnmshared => ../dnmshared
|
||||
)
|
||||
|
@@ -45,6 +45,8 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0 h1:5B0uxl2lzNRVkJVg+uGHxWtRt4C0Wjc6kJKo5XYx8xE=
|
||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 h1:v8lWpj5957KtDMKu+xQtlu6G3ZoZR6Tn9bsfZCRG5Xw=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0/go.mod h1:GAX7tMJqXx9fB1BrsTWPOXy6IBRX+J461BffVPAdpwo=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
@@ -55,12 +57,18 @@ github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRU
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE=
|
||||
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/solarlune/resolv v0.5.1 h1:Ul6PAs/zaxiMUOEYz1Z6VeUj5k3CDcWMvSh+kivybDY=
|
||||
github.com/solarlune/resolv v0.5.1/go.mod h1:HjM2f/0NoVjVdZsi26GtugX5aFbA62COEFEXkOhveRw=
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713 h1:knaxjm6QMbUMNvuaSnJZmw0gRX4V/79JVUQiziJGM84=
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713/go.mod h1:mlR+dHGb+4YgXkf13rkQTuzrneeHANxOm6+ZnEV9HsA=
|
||||
github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w=
|
||||
@@ -71,6 +79,8 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
|
@@ -10,8 +10,6 @@ import (
|
||||
"server/api"
|
||||
"server/api/v1"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
"server/configs"
|
||||
"server/env_tools"
|
||||
"server/models"
|
||||
"server/storage"
|
||||
@@ -19,6 +17,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
. "dnmshared"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/robfig/cron"
|
||||
@@ -30,8 +30,6 @@ func main() {
|
||||
MustParseConstants()
|
||||
storage.Init()
|
||||
env_tools.LoadPreConf()
|
||||
utils.InitWechat(configs.WechatConfigIns)
|
||||
utils.InitWechatGame(configs.WechatGameConfigIns)
|
||||
if Conf.General.ServerEnv == SERVER_ENV_TEST {
|
||||
env_tools.MergeTestPlayerAccounts()
|
||||
}
|
||||
|
@@ -1,13 +1,9 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/ByteArena/box2d"
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
type Barrier struct {
|
||||
X float64
|
||||
Y float64
|
||||
Type uint32
|
||||
Boundary *Polygon2D
|
||||
CollidableBody *box2d.B2Body
|
||||
Boundary *Polygon2D
|
||||
}
|
||||
|
@@ -1,19 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/ByteArena/box2d"
|
||||
)
|
||||
|
||||
type Bullet struct {
|
||||
LocalIdInBattle int32 `json:"-"`
|
||||
LinearSpeed float64 `json:"-"`
|
||||
X float64 `json:"-"`
|
||||
Y float64 `json:"-"`
|
||||
Removed bool `json:"-"`
|
||||
Dir *Direction `json:"-"`
|
||||
StartAtPoint *Vec2D `json:"-"`
|
||||
EndAtPoint *Vec2D `json:"-"`
|
||||
DamageBoundary *Polygon2D `json:"-"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
RemovedAtFrameId int32 `json:"-"`
|
||||
}
|
@@ -86,7 +86,7 @@ func (p *InRangePlayerCollection) NextPlayerToAttack() *InRangePlayerNode {
|
||||
|
||||
//TODO: 完成重构
|
||||
|
||||
/// Doubly circular linked list Implement
|
||||
// / Doubly circular linked list Implement
|
||||
type InRangePlayerNode struct {
|
||||
Prev *InRangePlayerNode
|
||||
Next *InRangePlayerNode
|
||||
|
@@ -1,132 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ByteArena/box2d"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Use type `float64` for json unmarshalling of numbers.
|
||||
type Direction struct {
|
||||
Dx int32 `json:"dx,omitempty"`
|
||||
Dy int32 `json:"dy,omitempty"`
|
||||
}
|
||||
|
||||
type Vec2D struct {
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
}
|
||||
|
||||
func CreateVec2DFromB2Vec2(b2V2 box2d.B2Vec2) *Vec2D {
|
||||
return &Vec2D{
|
||||
X: b2V2.X,
|
||||
Y: b2V2.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (v2 *Vec2D) ToB2Vec2() box2d.B2Vec2 {
|
||||
return box2d.MakeB2Vec2(v2.X, v2.Y)
|
||||
}
|
||||
|
||||
type Polygon2D struct {
|
||||
Anchor *Vec2D `json:"-"` // This "Polygon2D.Anchor" is used to be assigned to "B2BodyDef.Position", which in turn is used as the position of the FIRST POINT of the polygon.
|
||||
Points []*Vec2D `json:"-"`
|
||||
|
||||
/*
|
||||
When used to represent a "polyline directly drawn in a `Tmx file`", we can initialize both "Anchor" and "Points" simultaneously.
|
||||
|
||||
Yet when used to represent a "polyline drawn in a `Tsx file`", we have to first initialize "Points w.r.t. center of the tile-rectangle", and then "Anchor(initially nil) of the tile positioned in the `Tmx file`".
|
||||
|
||||
Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for more information.
|
||||
*/
|
||||
|
||||
/*
|
||||
[WARNING] Used to cache "`TileWidth & TileHeight` of a Tsx file" only.
|
||||
*/
|
||||
TileWidth int
|
||||
TileHeight int
|
||||
|
||||
/*
|
||||
[WARNING] Used to cache "`Width & TileHeight` of an object in Tmx file" only.
|
||||
*/
|
||||
TmxObjectWidth float64
|
||||
TmxObjectHeight float64
|
||||
}
|
||||
|
||||
func MoveDynamicBody(body *box2d.B2Body, pToTargetPos *box2d.B2Vec2, inSeconds float64) {
|
||||
if body.GetType() != box2d.B2BodyType.B2_dynamicBody {
|
||||
return
|
||||
}
|
||||
body.SetTransform(*pToTargetPos, 0.0)
|
||||
body.SetLinearVelocity(box2d.MakeB2Vec2(0.0, 0.0))
|
||||
body.SetAngularVelocity(0.0)
|
||||
}
|
||||
|
||||
func PrettyPrintFixture(fix *box2d.B2Fixture) {
|
||||
fmt.Printf("\t\tfriction:\t%v\n", fix.M_friction)
|
||||
fmt.Printf("\t\trestitution:\t%v\n", fix.M_restitution)
|
||||
fmt.Printf("\t\tdensity:\t%v\n", fix.M_density)
|
||||
fmt.Printf("\t\tisSensor:\t%v\n", fix.M_isSensor)
|
||||
fmt.Printf("\t\tfilter.categoryBits:\t%d\n", fix.M_filter.CategoryBits)
|
||||
fmt.Printf("\t\tfilter.maskBits:\t%d\n", fix.M_filter.MaskBits)
|
||||
fmt.Printf("\t\tfilter.groupIndex:\t%d\n", fix.M_filter.GroupIndex)
|
||||
|
||||
switch fix.M_shape.GetType() {
|
||||
case box2d.B2Shape_Type.E_circle:
|
||||
{
|
||||
s := fix.M_shape.(*box2d.B2CircleShape)
|
||||
fmt.Printf("\t\tb2CircleShape shape: {\n")
|
||||
fmt.Printf("\t\t\tradius:\t%v\n", s.M_radius)
|
||||
fmt.Printf("\t\t\toffset:\t%v\n", s.M_p)
|
||||
fmt.Printf("\t\t}\n")
|
||||
}
|
||||
break
|
||||
|
||||
case box2d.B2Shape_Type.E_polygon:
|
||||
{
|
||||
s := fix.M_shape.(*box2d.B2PolygonShape)
|
||||
fmt.Printf("\t\tb2PolygonShape shape: {\n")
|
||||
for i := 0; i < s.M_count; i++ {
|
||||
fmt.Printf("\t\t\t%v\n", s.M_vertices[i])
|
||||
}
|
||||
fmt.Printf("\t\t}\n")
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func PrettyPrintBody(body *box2d.B2Body) {
|
||||
bodyIndex := body.M_islandIndex
|
||||
|
||||
fmt.Printf("{\n")
|
||||
fmt.Printf("\tHeapRAM addr:\t%p\n", body)
|
||||
fmt.Printf("\ttype:\t%d\n", body.M_type)
|
||||
fmt.Printf("\tposition:\t%v\n", body.GetPosition())
|
||||
fmt.Printf("\tangle:\t%v\n", body.M_sweep.A)
|
||||
fmt.Printf("\tlinearVelocity:\t%v\n", body.GetLinearVelocity())
|
||||
fmt.Printf("\tangularVelocity:\t%v\n", body.GetAngularVelocity())
|
||||
fmt.Printf("\tlinearDamping:\t%v\n", body.M_linearDamping)
|
||||
fmt.Printf("\tangularDamping:\t%v\n", body.M_angularDamping)
|
||||
fmt.Printf("\tallowSleep:\t%d\n", body.M_flags&box2d.B2Body_Flags.E_autoSleepFlag)
|
||||
fmt.Printf("\tawake:\t%d\n", body.M_flags&box2d.B2Body_Flags.E_awakeFlag)
|
||||
fmt.Printf("\tfixedRotation:\t%d\n", body.M_flags&box2d.B2Body_Flags.E_fixedRotationFlag)
|
||||
fmt.Printf("\tbullet:\t%d\n", body.M_flags&box2d.B2Body_Flags.E_bulletFlag)
|
||||
fmt.Printf("\tactive:\t%d\n", body.M_flags&box2d.B2Body_Flags.E_activeFlag)
|
||||
fmt.Printf("\tgravityScale:\t%v\n", body.M_gravityScale)
|
||||
fmt.Printf("\tislandIndex:\t%v\n", bodyIndex)
|
||||
fmt.Printf("\tfixtures: {\n")
|
||||
for f := body.M_fixtureList; f != nil; f = f.M_next {
|
||||
PrettyPrintFixture(f)
|
||||
}
|
||||
fmt.Printf("\t}\n")
|
||||
fmt.Printf("}\n")
|
||||
}
|
||||
|
||||
func Distance(pt1 *Vec2D, pt2 *Vec2D) float64 {
|
||||
dx := pt1.X - pt2.X
|
||||
dy := pt1.Y - pt2.Y
|
||||
return math.Sqrt(dx*dx + dy*dy)
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
pb "server/pb_output"
|
||||
)
|
||||
|
||||
@@ -33,6 +34,14 @@ func toPbVec2DList(modelInstance *Vec2DList) *pb.Vec2DList {
|
||||
return toRet
|
||||
}
|
||||
|
||||
func ToPbVec2DListMap(modelInstances map[string]*Vec2DList) map[string]*pb.Vec2DList {
|
||||
toRet := make(map[string]*pb.Vec2DList, len(modelInstances))
|
||||
for k, v := range modelInstances {
|
||||
toRet[k] = toPbVec2DList(v)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbPolygon2DList(modelInstance *Polygon2DList) *pb.Polygon2DList {
|
||||
toRet := &pb.Polygon2DList{
|
||||
Polygon2DList: make([]*pb.Polygon2D, len(*modelInstance)),
|
||||
@@ -43,24 +52,10 @@ func toPbPolygon2DList(modelInstance *Polygon2DList) *pb.Polygon2DList {
|
||||
return toRet
|
||||
}
|
||||
|
||||
func ToPbStrToBattleColliderInfo(intervalToPing int32, willKickIfInactiveFor int32, boundRoomId int32, stageName string, modelInstance1 StrToVec2DListMap, modelInstance2 StrToPolygon2DListMap, stageDiscreteW int32, stageDiscreteH int32, stageTileW int32, stageTileH int32) *pb.BattleColliderInfo {
|
||||
toRet := &pb.BattleColliderInfo{
|
||||
IntervalToPing: intervalToPing,
|
||||
WillKickIfInactiveFor: willKickIfInactiveFor,
|
||||
BoundRoomId: boundRoomId,
|
||||
StageName: stageName,
|
||||
StrToVec2DListMap: make(map[string]*pb.Vec2DList, 0),
|
||||
StrToPolygon2DListMap: make(map[string]*pb.Polygon2DList, 0),
|
||||
StageDiscreteW: stageDiscreteW,
|
||||
StageDiscreteH: stageDiscreteH,
|
||||
StageTileW: stageTileW,
|
||||
StageTileH: stageTileH,
|
||||
}
|
||||
for k, v := range modelInstance1 {
|
||||
toRet.StrToVec2DListMap[k] = toPbVec2DList(v)
|
||||
}
|
||||
for k, v := range modelInstance2 {
|
||||
toRet.StrToPolygon2DListMap[k] = toPbPolygon2DList(v)
|
||||
func ToPbPolygon2DListMap(modelInstances map[string]*Polygon2DList) map[string]*pb.Polygon2DList {
|
||||
toRet := make(map[string]*pb.Polygon2DList, len(modelInstances))
|
||||
for k, v := range modelInstances {
|
||||
toRet[k] = toPbPolygon2DList(v)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
@@ -90,114 +85,3 @@ func toPbPlayers(modelInstances map[int32]*Player) map[int32]*pb.Player {
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbTreasures(modelInstances map[int32]*Treasure) map[int32]*pb.Treasure {
|
||||
toRet := make(map[int32]*pb.Treasure, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &pb.Treasure{
|
||||
Id: last.Id,
|
||||
LocalIdInBattle: last.LocalIdInBattle,
|
||||
Score: last.Score,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Removed: last.Removed,
|
||||
Type: last.Type,
|
||||
}
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbTraps(modelInstances map[int32]*Trap) map[int32]*pb.Trap {
|
||||
toRet := make(map[int32]*pb.Trap, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &pb.Trap{
|
||||
Id: last.Id,
|
||||
LocalIdInBattle: last.LocalIdInBattle,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Removed: last.Removed,
|
||||
Type: last.Type,
|
||||
}
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbBullets(modelInstances map[int32]*Bullet) map[int32]*pb.Bullet {
|
||||
toRet := make(map[int32]*pb.Bullet, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
for k, last := range modelInstances {
|
||||
if nil == last.StartAtPoint || nil == last.EndAtPoint {
|
||||
continue
|
||||
}
|
||||
toRet[k] = &pb.Bullet{
|
||||
LocalIdInBattle: last.LocalIdInBattle,
|
||||
LinearSpeed: last.LinearSpeed,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Removed: last.Removed,
|
||||
StartAtPoint: &pb.Vec2D{
|
||||
X: last.StartAtPoint.X,
|
||||
Y: last.StartAtPoint.Y,
|
||||
},
|
||||
EndAtPoint: &pb.Vec2D{
|
||||
X: last.EndAtPoint.X,
|
||||
Y: last.EndAtPoint.Y,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbSpeedShoes(modelInstances map[int32]*SpeedShoe) map[int32]*pb.SpeedShoe {
|
||||
toRet := make(map[int32]*pb.SpeedShoe, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &pb.SpeedShoe{
|
||||
Id: last.Id,
|
||||
LocalIdInBattle: last.LocalIdInBattle,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Removed: last.Removed,
|
||||
Type: last.Type,
|
||||
}
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbGuardTowers(modelInstances map[int32]*GuardTower) map[int32]*pb.GuardTower {
|
||||
toRet := make(map[int32]*pb.GuardTower, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &pb.GuardTower{
|
||||
Id: last.Id,
|
||||
LocalIdInBattle: last.LocalIdInBattle,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Removed: last.Removed,
|
||||
Type: last.Type,
|
||||
}
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
@@ -2,8 +2,8 @@ package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"github.com/ByteArena/box2d"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
@@ -37,7 +37,7 @@ type Player struct {
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Dir *Direction `json:"dir,omitempty"`
|
||||
Speed int32 `json:"speed,omitempty"`
|
||||
Speed float64 `json:"speed,omitempty"`
|
||||
BattleState int32 `json:"battleState,omitempty"`
|
||||
LastMoveGmtMillis int32 `json:"lastMoveGmtMillis,omitempty"`
|
||||
Score int32 `json:"score,omitempty"`
|
||||
@@ -48,16 +48,15 @@ type Player struct {
|
||||
DisplayName string `json:"displayName,omitempty" db:"display_name"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
|
||||
FrozenAtGmtMillis int64 `json:"-" db:"-"`
|
||||
AddSpeedAtGmtMillis int64 `json:"-" db:"-"`
|
||||
CreatedAt int64 `json:"-" db:"created_at"`
|
||||
UpdatedAt int64 `json:"-" db:"updated_at"`
|
||||
DeletedAt NullInt64 `json:"-" db:"deleted_at"`
|
||||
TutorialStage int `json:"-" db:"tutorial_stage"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
AckingFrameId int32 `json:"ackingFrameId"`
|
||||
AckingInputFrameId int32 `json:"-"`
|
||||
LastSentInputFrameId int32 `json:"-"`
|
||||
FrozenAtGmtMillis int64 `json:"-" db:"-"`
|
||||
AddSpeedAtGmtMillis int64 `json:"-" db:"-"`
|
||||
CreatedAt int64 `json:"-" db:"created_at"`
|
||||
UpdatedAt int64 `json:"-" db:"updated_at"`
|
||||
DeletedAt NullInt64 `json:"-" db:"deleted_at"`
|
||||
TutorialStage int `json:"-" db:"tutorial_stage"`
|
||||
AckingFrameId int32 `json:"ackingFrameId"`
|
||||
AckingInputFrameId int32 `json:"-"`
|
||||
LastSentInputFrameId int32 `json:"-"`
|
||||
}
|
||||
|
||||
func ExistPlayerByName(name string) (bool, error) {
|
||||
|
@@ -2,7 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
. "server/common"
|
||||
. "dnmshared"
|
||||
"server/storage"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
@@ -2,6 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
. "dnmshared"
|
||||
"errors"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
|
@@ -1,14 +0,0 @@
|
||||
package models
|
||||
|
||||
import "github.com/ByteArena/box2d"
|
||||
|
||||
type Pumpkin struct {
|
||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
||||
LinearSpeed float64 `json:"linearSpeed,omitempty"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
Dir *Direction `json:"-"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
RemovedAtFrameId int32 `json:"-"`
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
package models
|
||||
|
||||
type RingBuffer struct {
|
||||
Ed int32 // write index
|
||||
St int32 // read index
|
||||
Ed int32 // write index, open index
|
||||
St int32 // read index, closed index
|
||||
EdFrameId int32
|
||||
StFrameId int32
|
||||
N int32
|
||||
|
@@ -2,10 +2,9 @@ package models
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"go.uber.org/zap"
|
||||
. "server/common"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -92,43 +91,13 @@ func InitRoomHeapManager() {
|
||||
|
||||
for i := 0; i < initialCountOfRooms; i++ {
|
||||
roomCapacity := 2
|
||||
joinIndexBooleanArr := make([]bool, roomCapacity)
|
||||
for index, _ := range joinIndexBooleanArr {
|
||||
joinIndexBooleanArr[index] = false
|
||||
}
|
||||
currentRoomBattleState := RoomBattleStateIns.IDLE
|
||||
pq[i] = &Room{
|
||||
Id: int32(i + 1),
|
||||
Players: make(map[int32]*Player),
|
||||
PlayerDownsyncSessionDict: make(map[int32]*websocket.Conn),
|
||||
PlayerSignalToCloseDict: make(map[int32]SignalToCloseConnCbType),
|
||||
Capacity: roomCapacity,
|
||||
Score: calRoomScore(0, roomCapacity, currentRoomBattleState),
|
||||
State: currentRoomBattleState,
|
||||
Index: i,
|
||||
Tick: 0,
|
||||
EffectivePlayerCount: 0,
|
||||
//BattleDurationNanos: int64(5 * 1000 * 1000 * 1000),
|
||||
BattleDurationNanos: int64(30 * 1000 * 1000 * 1000),
|
||||
ServerFPS: 60,
|
||||
Treasures: make(map[int32]*Treasure),
|
||||
Traps: make(map[int32]*Trap),
|
||||
GuardTowers: make(map[int32]*GuardTower),
|
||||
Bullets: make(map[int32]*Bullet),
|
||||
SpeedShoes: make(map[int32]*SpeedShoe),
|
||||
Barriers: make(map[int32]*Barrier),
|
||||
Pumpkins: make(map[int32]*Pumpkin),
|
||||
AccumulatedLocalIdForBullets: 0,
|
||||
AllPlayerInputsBuffer: NewRingBuffer(1024),
|
||||
LastAllConfirmedInputFrameId: -1,
|
||||
LastAllConfirmedInputFrameIdWithChange: -1,
|
||||
LastAllConfirmedInputList: make([]uint64, roomCapacity),
|
||||
InputDelayFrames: 4,
|
||||
InputScaleFrames: 2,
|
||||
JoinIndexBooleanArr: joinIndexBooleanArr,
|
||||
Id: int32(i + 1),
|
||||
Capacity: roomCapacity,
|
||||
Index: i,
|
||||
}
|
||||
roomMap[pq[i].Id] = pq[i]
|
||||
pq[i].ChooseStage()
|
||||
pq[i].OnDismissed()
|
||||
}
|
||||
heap.Init(&pq)
|
||||
RoomHeapManagerIns = &pq
|
||||
|
@@ -1,17 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/ByteArena/box2d"
|
||||
)
|
||||
|
||||
type SpeedShoe struct {
|
||||
Id int32 `json:"id,omitempty"`
|
||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
Type int32 `json:"type,omitempty"`
|
||||
PickupBoundary *Polygon2D `json:"-"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
RemovedAtFrameId int32 `json:"-"`
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/ByteArena/box2d"
|
||||
)
|
||||
|
||||
type Trap struct {
|
||||
Id int32 `json:"id,omitempty"`
|
||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
||||
Type int32 `json:"type,omitempty"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
PickupBoundary *Polygon2D `json:"-"`
|
||||
TrapBullets []*Bullet `json:"-"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
RemovedAtFrameId int32 `json:"-"`
|
||||
}
|
||||
|
||||
type GuardTower struct {
|
||||
Id int32 `json:"id,omitempty"`
|
||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
||||
Type int32 `json:"type,omitempty"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
PickupBoundary *Polygon2D `json:"-"`
|
||||
TrapBullets []*Bullet `json:"-"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
RemovedAtFrameId int32 `json:"-"`
|
||||
|
||||
InRangePlayers *InRangePlayerCollection `json:"-"`
|
||||
LastAttackTick int64 `json:"-"`
|
||||
|
||||
TileWidth float64 `json:"-"`
|
||||
TileHeight float64 `json:"-"`
|
||||
WidthInB2World float64 `json:"-"`
|
||||
HeightInB2World float64 `json:"-"`
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/ByteArena/box2d"
|
||||
)
|
||||
|
||||
type Treasure struct {
|
||||
Id int32 `json:"id,omitempty"`
|
||||
LocalIdInBattle int32 `json:"localIdInBattle,omitempty"`
|
||||
Score int32 `json:"score,omitempty"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
Type int32 `json:"type,omitempty"`
|
||||
|
||||
PickupBoundary *Polygon2D `json:"-"`
|
||||
CollidableBody *box2d.B2Body `json:"-"`
|
||||
}
|
@@ -6,6 +6,8 @@ import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -15,8 +17,12 @@ var (
|
||||
func initMySQL() {
|
||||
var err error
|
||||
MySQLManagerIns, err = sqlx.Connect("mysql", Conf.MySQL.DSN+"?charset=utf8mb4")
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
err = MySQLManagerIns.Ping()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
Logger.Info("MySQLManagerIns", zap.Any("mysql", MySQLManagerIns))
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/go-redis/redis"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,6 +22,8 @@ func initRedis() {
|
||||
DB: Conf.Redis.Dbname, // use default DB
|
||||
})
|
||||
pong, err := RedisManagerIns.Ping().Result()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
Logger.Info("Redis", zap.String("ping", pong))
|
||||
}
|
||||
|
@@ -17,7 +17,9 @@ func loadTMX(fp string, pTmxMapIns *models.TmxMap) {
|
||||
}
|
||||
|
||||
byteArr, err := ioutil.ReadFile(fp)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
models.DeserializeToTmxMapIns(byteArr, pTmxMapIns)
|
||||
for _, info := range pTmxMapIns.TreasuresInfo {
|
||||
fmt.Printf("treasuresInfo: %v\n", info)
|
||||
@@ -33,7 +35,9 @@ func loadTSX(fp string, pTsxIns *models.Tsx) {
|
||||
}
|
||||
|
||||
byteArr, err := ioutil.ReadFile(fp)
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
models.DeserializeToTsxIns(byteArr, pTsxIns)
|
||||
for _, Pos := range pTsxIns.TrapPolyLineList {
|
||||
fmt.Printf("%v\n", Pos)
|
||||
@@ -43,10 +47,14 @@ func loadTSX(fp string, pTsxIns *models.Tsx) {
|
||||
func getTMXInfo() {
|
||||
relativePath = "../frontend/assets/resources/map/treasurehunter.tmx"
|
||||
execPath, err := os.Executable()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("execPath = %v, pwd = %s, returning...\n", execPath, pwd)
|
||||
|
||||
@@ -61,10 +69,14 @@ func getTSXInfo() {
|
||||
|
||||
relativePath = "../frontend/assets/resources/map/tile_1.tsx"
|
||||
execPath, err := os.Executable()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("execPath = %v, pwd = %s, returning...\n", execPath, pwd)
|
||||
tsxIns := models.Tsx{}
|
||||
|
@@ -14,6 +14,8 @@ import (
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -240,16 +242,40 @@ func Serve(c *gin.Context) {
|
||||
})
|
||||
}()
|
||||
|
||||
playerBattleColliderInfo := models.ToPbStrToBattleColliderInfo(int32(Constants.Ws.IntervalToPing), int32(Constants.Ws.WillKickIfInactiveFor), pRoom.Id, pRoom.StageName, pRoom.RawBattleStrToVec2DListMap, pRoom.RawBattleStrToPolygon2DListMap, pRoom.StageDiscreteW, pRoom.StageDiscreteH, pRoom.StageTileW, pRoom.StageTileH)
|
||||
// Construct "battleColliderInfo" to downsync
|
||||
bciFrame := &pb.BattleColliderInfo{
|
||||
BoundRoomId: pRoom.Id,
|
||||
StageName: pRoom.StageName,
|
||||
StrToVec2DListMap: models.ToPbVec2DListMap(pRoom.RawBattleStrToVec2DListMap),
|
||||
StrToPolygon2DListMap: models.ToPbPolygon2DListMap(pRoom.RawBattleStrToPolygon2DListMap),
|
||||
StageDiscreteW: pRoom.StageDiscreteW,
|
||||
StageDiscreteH: pRoom.StageDiscreteH,
|
||||
StageTileW: pRoom.StageTileW,
|
||||
StageTileH: pRoom.StageTileH,
|
||||
|
||||
IntervalToPing: int32(Constants.Ws.IntervalToPing),
|
||||
WillKickIfInactiveFor: int32(Constants.Ws.WillKickIfInactiveFor),
|
||||
BattleDurationNanos: pRoom.BattleDurationNanos,
|
||||
ServerFps: pRoom.ServerFps,
|
||||
InputDelayFrames: pRoom.InputDelayFrames,
|
||||
InputScaleFrames: pRoom.InputScaleFrames,
|
||||
NstDelayFrames: pRoom.NstDelayFrames,
|
||||
InputFrameUpsyncDelayTolerance: pRoom.InputFrameUpsyncDelayTolerance,
|
||||
MaxChasingRenderFramesPerUpdate: pRoom.MaxChasingRenderFramesPerUpdate,
|
||||
PlayerBattleState: pThePlayer.BattleState, // For frontend to know whether it's rejoining
|
||||
RollbackEstimatedDt: pRoom.RollbackEstimatedDt,
|
||||
RollbackEstimatedDtMillis: pRoom.RollbackEstimatedDtMillis,
|
||||
RollbackEstimatedDtNanos: pRoom.RollbackEstimatedDtNanos,
|
||||
}
|
||||
|
||||
resp := &pb.WsResp{
|
||||
Ret: int32(Constants.RetCode.Ok),
|
||||
EchoedMsgId: int32(0),
|
||||
Act: models.DOWNSYNC_MSG_ACT_HB_REQ,
|
||||
BciFrame: playerBattleColliderInfo,
|
||||
BciFrame: bciFrame,
|
||||
}
|
||||
|
||||
// Logger.Info("Sending downsync HeartbeatRequirements:", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("resp", resp))
|
||||
Logger.Debug("Sending downsync HeartbeatRequirements:", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("resp", resp))
|
||||
|
||||
theBytes, marshalErr := proto.Marshal(resp)
|
||||
if nil != marshalErr {
|
||||
|
21
collider_visualizer/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
PROJECTNAME=viscol.exe
|
||||
ROOT_DIR=.
|
||||
all: help
|
||||
## Available proxies for downloading go modules are listed in "https://github.com/golang/go/wiki/Modules#how-do-i-use-vendoring-with-modules-is-vendoring-going-away".
|
||||
GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
|
||||
build:
|
||||
go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
run: build
|
||||
./$(PROJECTNAME)
|
||||
|
||||
.PHONY: help
|
||||
|
||||
help: Makefile
|
||||
@echo
|
||||
@echo " Choose a command run:"
|
||||
@echo
|
||||
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
|
||||
@echo
|
||||
|
52
collider_visualizer/common.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/solarlune/resolv"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
var (
|
||||
PolygonFillerImage = ebiten.NewImage(1, 1)
|
||||
)
|
||||
|
||||
func DrawPolygon(screen *ebiten.Image, shape *resolv.ConvexPolygon, clr color.Color) {
|
||||
PolygonFillerImage.Fill(clr)
|
||||
indices := []uint16{}
|
||||
vs := []ebiten.Vertex{}
|
||||
coors := shape.Transformed()
|
||||
centerX := float64(0)
|
||||
centerY := float64(0)
|
||||
n := uint16(len(coors))
|
||||
for i, coor := range coors {
|
||||
centerX += coor.X()
|
||||
centerY += coor.Y()
|
||||
vs = append(vs, ebiten.Vertex{
|
||||
DstX: float32(coor.X()),
|
||||
DstY: float32(coor.Y()),
|
||||
SrcX: 0,
|
||||
SrcY: 0,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
})
|
||||
indices = append(indices, uint16(i), uint16(i+1)%n, n)
|
||||
}
|
||||
|
||||
centerX = centerX / float64(n)
|
||||
centerY = centerY / float64(n)
|
||||
|
||||
vs = append(vs, ebiten.Vertex{
|
||||
DstX: float32(centerX),
|
||||
DstY: float32(centerY),
|
||||
SrcX: 0,
|
||||
SrcY: 0,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
})
|
||||
|
||||
screen.DrawTriangles(vs, indices, PolygonFillerImage, nil)
|
||||
}
|
BIN
collider_visualizer/excel.ttf
Normal file
27
collider_visualizer/go.mod
Normal file
@@ -0,0 +1,27 @@
|
||||
module viscol
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/hajimehoshi/ebiten/v2 v2.4.7
|
||||
github.com/solarlune/resolv v0.5.1
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
|
||||
dnmshared v0.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ebitengine/purego v0.0.0-20220905075623-aeed57cda744 // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad // indirect
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41 // indirect
|
||||
github.com/jezek/xgb v1.0.1 // indirect
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 // indirect
|
||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect
|
||||
)
|
||||
|
||||
replace dnmshared => ../dnmshared
|
96
collider_visualizer/go.sum
Normal file
@@ -0,0 +1,96 @@
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ebitengine/purego v0.0.0-20220905075623-aeed57cda744 h1:A8UnJ/5OKzki4HBDwoRQz7I6sxKsokpMXcGh+fUxpfc=
|
||||
github.com/ebitengine/purego v0.0.0-20220905075623-aeed57cda744/go.mod h1:Eh8I3yvknDYZeCuXH9kRNaPuHEwvXDCk378o9xszmHg=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad h1:kX51IjbsJPCvzV9jUoVQG9GEUqIq5hjfYzXTqQ52Rh8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.2.1 h1:y7zcy02/UgO24IL3COqYtrRZzhRucNBtmCo/SNU648k=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.2.1/go.mod h1:wjrYAy8vKgj9JsFgnYAOK346/uvE22TlmqouzdnYIs0=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.4.7 h1:XuvB7R0Rbw/O7g6vNU8gqr5b9e7MNhhAONMSsyreLDI=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.4.7/go.mod h1:Ofk1EfQZZ8tL0TlEPF5wPrnN+8Oa/ywuQOYh+uYsqLQ=
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41 h1:s01qIIRG7vN/5ndLwkDktjx44ulFk6apvAjVBYR50Yo=
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
|
||||
github.com/hajimehoshi/go-mp3 v0.3.3/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo=
|
||||
github.com/jakecoffman/cp v1.2.1/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
|
||||
github.com/jezek/xgb v1.0.1 h1:YUGhxps0aR7J2Xplbs23OHnV1mWaxFVcOl9b+1RQkt8=
|
||||
github.com/jezek/xgb v1.0.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||
github.com/jfreymuth/oggvorbis v1.0.4/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 h1:v8lWpj5957KtDMKu+xQtlu6G3ZoZR6Tn9bsfZCRG5Xw=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0/go.mod h1:GAX7tMJqXx9fB1BrsTWPOXy6IBRX+J461BffVPAdpwo=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/solarlune/resolv v0.5.1 h1:Ul6PAs/zaxiMUOEYz1Z6VeUj5k3CDcWMvSh+kivybDY=
|
||||
github.com/solarlune/resolv v0.5.1/go.mod h1:HjM2f/0NoVjVdZsi26GtugX5aFbA62COEFEXkOhveRw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 h1:3vUV5x5+3LfQbgk7paCM6INOaJG9xXQbn79xoNkwfIk=
|
||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U=
|
||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
171
collider_visualizer/main.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"image/color"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/text"
|
||||
"github.com/solarlune/resolv"
|
||||
"golang.org/x/image/font"
|
||||
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
func parseStage(stageName string) (int32, int32, int32, int32, StrToVec2DListMap, StrToPolygon2DListMap, error) {
|
||||
pwd, err := os.Getwd()
|
||||
if nil != err {
|
||||
Logger.Error("Failed to get current working dir:", zap.Any("pwd", pwd), zap.Any("err", err))
|
||||
}
|
||||
|
||||
relativePathForAllStages := "../frontend/assets/resources/map"
|
||||
relativePathForChosenStage := fmt.Sprintf("%s/%s", relativePathForAllStages, stageName)
|
||||
|
||||
pTmxMapIns := &TmxMap{}
|
||||
|
||||
absDirPathContainingDirectlyTmxFile := filepath.Join(pwd, relativePathForChosenStage)
|
||||
absTmxFilePath := fmt.Sprintf("%s/map.tmx", absDirPathContainingDirectlyTmxFile)
|
||||
if !filepath.IsAbs(absTmxFilePath) {
|
||||
panic("Tmx filepath must be absolute!")
|
||||
}
|
||||
|
||||
byteArr, err := ioutil.ReadFile(absTmxFilePath)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
err = xml.Unmarshal(byteArr, pTmxMapIns)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Obtain the content of `gidBoundariesMapInB2World`.
|
||||
gidBoundariesMapInB2World := make(map[int]StrToPolygon2DListMap, 0)
|
||||
for _, tileset := range pTmxMapIns.Tilesets {
|
||||
relativeTsxFilePath := fmt.Sprintf("%s/%s", filepath.Join(pwd, relativePathForChosenStage), tileset.Source) // Note that "TmxTileset.Source" can be a string of "relative path".
|
||||
absTsxFilePath, err := filepath.Abs(relativeTsxFilePath)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
if !filepath.IsAbs(absTsxFilePath) {
|
||||
panic("Filepath must be absolute!")
|
||||
}
|
||||
|
||||
byteArrOfTsxFile, err := ioutil.ReadFile(absTsxFilePath)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
DeserializeTsxToColliderDict(pTmxMapIns, byteArrOfTsxFile, int(tileset.FirstGid), gidBoundariesMapInB2World)
|
||||
}
|
||||
|
||||
return ParseTmxLayersAndGroups(pTmxMapIns, gidBoundariesMapInB2World)
|
||||
}
|
||||
|
||||
//go:embed excel.ttf
|
||||
var excelFont []byte
|
||||
|
||||
type Game struct {
|
||||
World WorldInterface
|
||||
Width, Height int
|
||||
Debug bool
|
||||
ShowHelpText bool
|
||||
Screen *ebiten.Image
|
||||
FontFace font.Face
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
|
||||
stageName := "simple" // Use this for calibration
|
||||
// stageName := "richsoil"
|
||||
stageDiscreteW, stageDiscreteH, stageTileW, stageTileH, playerPosMap, barrierMap, err := parseStage(stageName)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
PolygonFillerImage.Fill(color.RGBA{60, 60, 60, 255}) // Required to init color of the polygons!
|
||||
|
||||
spaceW := stageDiscreteW * stageTileW
|
||||
spaceH := stageDiscreteH * stageTileH
|
||||
|
||||
ebiten.SetWindowResizable(true)
|
||||
ebiten.SetWindowTitle("resolv test")
|
||||
|
||||
g := &Game{
|
||||
Width: int(spaceW),
|
||||
Height: int(spaceH),
|
||||
ShowHelpText: true,
|
||||
}
|
||||
|
||||
g.World = NewWorldColliderDisplay(g, stageDiscreteW, stageDiscreteH, stageTileW, stageTileH, playerPosMap, barrierMap)
|
||||
|
||||
fontData, _ := truetype.Parse(excelFont)
|
||||
|
||||
g.FontFace = truetype.NewFace(fontData, &truetype.Options{Size: 10})
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
g.World.Update()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
g.Screen = screen
|
||||
screen.Fill(color.RGBA{20, 20, 40, 255})
|
||||
g.World.Draw(screen)
|
||||
}
|
||||
|
||||
func (g *Game) DrawText(screen *ebiten.Image, x, y int, textLines ...string) {
|
||||
rectHeight := 10
|
||||
for _, txt := range textLines {
|
||||
w := float64(font.MeasureString(g.FontFace, txt).Round())
|
||||
ebitenutil.DrawRect(screen, float64(x), float64(y-8), w, float64(rectHeight), color.RGBA{0, 0, 0, 192})
|
||||
|
||||
text.Draw(screen, txt, g.FontFace, x+1, y+1, color.RGBA{0, 0, 150, 255})
|
||||
text.Draw(screen, txt, g.FontFace, x, y, color.RGBA{100, 150, 255, 255})
|
||||
y += rectHeight
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) DebugDraw(screen *ebiten.Image, space *resolv.Space) {
|
||||
|
||||
for y := 0; y < space.Height(); y++ {
|
||||
for x := 0; x < space.Width(); x++ {
|
||||
cell := space.Cell(x, y)
|
||||
|
||||
cw := float64(space.CellWidth)
|
||||
ch := float64(space.CellHeight)
|
||||
cx := float64(cell.X) * cw
|
||||
cy := float64(cell.Y) * ch
|
||||
|
||||
drawColor := color.RGBA{20, 20, 20, 255}
|
||||
|
||||
if cell.Occupied() {
|
||||
drawColor = color.RGBA{255, 255, 0, 255}
|
||||
}
|
||||
|
||||
ebitenutil.DrawLine(screen, cx, cy, cx+cw, cy, drawColor)
|
||||
ebitenutil.DrawLine(screen, cx+cw, cy, cx+cw, cy+ch, drawColor)
|
||||
ebitenutil.DrawLine(screen, cx+cw, cy+ch, cx, cy+ch, drawColor)
|
||||
ebitenutil.DrawLine(screen, cx, cy+ch, cx, cy, drawColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Layout(w, h int) (int, int) {
|
||||
return g.Width, g.Height
|
||||
}
|
||||
|
||||
func main() {
|
||||
ebiten.RunGame(NewGame())
|
||||
}
|
111
collider_visualizer/worldColliderDisplay.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/solarlune/resolv"
|
||||
"go.uber.org/zap"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
type WorldColliderDisplay struct {
|
||||
Game *Game
|
||||
Space *resolv.Space
|
||||
}
|
||||
|
||||
func (world *WorldColliderDisplay) Init() {
|
||||
}
|
||||
|
||||
func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTileW, stageTileH int32, playerPosMap StrToVec2DListMap, barrierMap StrToPolygon2DListMap) *WorldColliderDisplay {
|
||||
|
||||
playerList := *(playerPosMap["PlayerStartingPos"])
|
||||
barrierList := *(barrierMap["Barrier"])
|
||||
|
||||
world := &WorldColliderDisplay{Game: game}
|
||||
|
||||
Logger.Info("Parsed variables", zap.Any("stageDiscreteW", stageDiscreteW), zap.Any("stageDiscreteH", stageDiscreteH), zap.Any("stageTileW", stageTileW), zap.Any("stageTileH", stageTileH))
|
||||
|
||||
spaceW := stageDiscreteW * stageTileW
|
||||
spaceH := stageDiscreteH * stageTileH
|
||||
|
||||
spaceOffsetX := float64(spaceW) * 0.5
|
||||
spaceOffsetY := float64(spaceH) * 0.5
|
||||
|
||||
playerColliderRadius := float64(32)
|
||||
playerColliders := make([]*resolv.Object, len(playerList))
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), 16, 16)
|
||||
for i, player := range playerList {
|
||||
playerCollider := GenerateRectCollider(player.X, player.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.X=%v, player.Y=%v, radius=%v, spaceOffsetX=%v, spaceOffsetY=%v, shape=%v; calibrationCheckX=player.X-radius+spaceOffsetX=%v", i, player.X, player.Y, playerColliderRadius, spaceOffsetX, spaceOffsetY, playerCollider.Shape, player.X-playerColliderRadius+spaceOffsetX))
|
||||
playerColliders[i] = playerCollider
|
||||
space.Add(playerCollider)
|
||||
}
|
||||
|
||||
barrierLocalId := 0
|
||||
for _, barrierUnaligned := range barrierList {
|
||||
barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, "Barrier")
|
||||
Logger.Info(fmt.Sprintf("Added barrier: shape=%v", barrierCollider.Shape))
|
||||
space.Add(barrierCollider)
|
||||
barrierLocalId++
|
||||
}
|
||||
|
||||
world.Space = space
|
||||
|
||||
moveToCollide := true
|
||||
if moveToCollide {
|
||||
toTestPlayerCollider := playerColliders[0]
|
||||
oldDx, oldDy := -2.98, -50.0
|
||||
dx, dy := oldDx, oldDy
|
||||
if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil {
|
||||
playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon)
|
||||
barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY := CalcPushbacks(oldDx, oldDy, playerShape, barrierShape); overlapped {
|
||||
Logger.Info(fmt.Sprintf("Collided & overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v, pushbackX=%v, pushbackY=%v", toTestPlayerCollider.X, toTestPlayerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY))
|
||||
dx -= pushbackX
|
||||
dy -= pushbackY
|
||||
} else {
|
||||
Logger.Info(fmt.Sprintf("Collider BUT not overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v", toTestPlayerCollider.X, toTestPlayerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape)))
|
||||
}
|
||||
}
|
||||
|
||||
toTestPlayerCollider.X += dx
|
||||
toTestPlayerCollider.Y += dy
|
||||
toTestPlayerCollider.Update()
|
||||
}
|
||||
|
||||
return world
|
||||
}
|
||||
|
||||
func (world *WorldColliderDisplay) Update() {
|
||||
|
||||
}
|
||||
|
||||
func (world *WorldColliderDisplay) Draw(screen *ebiten.Image) {
|
||||
|
||||
for _, o := range world.Space.Objects() {
|
||||
if o.HasTags("Player") {
|
||||
drawColor := color.RGBA{0, 255, 0, 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)
|
||||
|
||||
if world.Game.ShowHelpText {
|
||||
|
||||
world.Game.DrawText(screen, 16, 16,
|
||||
"~ Collider Display test ~",
|
||||
"F1: Toggle Debug View",
|
||||
"F2: Show / Hide help text",
|
||||
"R: Restart world",
|
||||
fmt.Sprintf("%d FPS (frames per second)", int(ebiten.CurrentFPS())),
|
||||
fmt.Sprintf("%d TPS (ticks per second)", int(ebiten.CurrentTPS())),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
9
collider_visualizer/worldinterface.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import "github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
type WorldInterface interface {
|
||||
Init()
|
||||
Update()
|
||||
Draw(*ebiten.Image)
|
||||
}
|
51
dnmshared/geometry.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package dnmshared
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Use type `float64` for json unmarshalling of numbers.
|
||||
type Direction struct {
|
||||
Dx int32 `json:"dx,omitempty"`
|
||||
Dy int32 `json:"dy,omitempty"`
|
||||
}
|
||||
|
||||
type Vec2D struct {
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
}
|
||||
|
||||
func NormVec2D(dx, dy float64) Vec2D {
|
||||
return Vec2D{dy, -dx}
|
||||
}
|
||||
|
||||
type Polygon2D struct {
|
||||
Anchor *Vec2D `json:"-"` // This "Polygon2D.Anchor" is used to be assigned to "B2BodyDef.Position", which in turn is used as the position of the FIRST POINT of the polygon.
|
||||
Points []*Vec2D `json:"-"`
|
||||
|
||||
/*
|
||||
When used to represent a "polyline directly drawn in a `Tmx file`", we can initialize both "Anchor" and "Points" simultaneously.
|
||||
|
||||
Yet when used to represent a "polyline drawn in a `Tsx file`", we have to first initialize "Points w.r.t. center of the tile-rectangle", and then "Anchor(initially nil) of the tile positioned in the `Tmx file`".
|
||||
|
||||
Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for more information.
|
||||
*/
|
||||
|
||||
/*
|
||||
[WARNING] Used to cache "`TileWidth & TileHeight` of a Tsx file" only.
|
||||
*/
|
||||
TileWidth int
|
||||
TileHeight int
|
||||
|
||||
/*
|
||||
[WARNING] Used to cache "`Width & TileHeight` of an object in Tmx file" only.
|
||||
*/
|
||||
TmxObjectWidth float64
|
||||
TmxObjectHeight float64
|
||||
}
|
||||
|
||||
func Distance(pt1 *Vec2D, pt2 *Vec2D) float64 {
|
||||
dx := pt1.X - pt2.X
|
||||
dy := pt1.Y - pt2.Y
|
||||
return math.Sqrt(dx*dx + dy*dy)
|
||||
}
|
3
dnmshared/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module tiled
|
||||
|
||||
go 1.19
|
@@ -1,4 +1,4 @@
|
||||
package common
|
||||
package dnmshared
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
@@ -19,5 +19,7 @@ func init() {
|
||||
LoggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
var err error
|
||||
Logger, err = LoggerConfig.Build()
|
||||
ErrFatal(err)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
}
|
220
dnmshared/resolv_helper.go
Normal file
@@ -0,0 +1,220 @@
|
||||
package dnmshared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kvartborg/vector"
|
||||
"github.com/solarlune/resolv"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
|
||||
var s []string = make([]string, len(body.Points))
|
||||
for i, p := range body.Points {
|
||||
s[i] = fmt.Sprintf("[%v, %v]", p[0]+body.X, p[1]+body.Y)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[%s]", strings.Join(s, ", "))
|
||||
}
|
||||
|
||||
func GenerateRectCollider(origX, origY, w, h, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||
collider := resolv.NewObject(origX-w*0.5+spaceOffsetX, origY-h*0.5+spaceOffsetY, w, h, tag)
|
||||
shape := resolv.NewRectangle(0, 0, w, h)
|
||||
collider.SetShape(shape)
|
||||
return collider
|
||||
}
|
||||
|
||||
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||
aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
|
||||
var w, h float64 = 0, 0
|
||||
|
||||
shape := resolv.NewConvexPolygon()
|
||||
for i, pi := range aligned.Points {
|
||||
for j, pj := range aligned.Points {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if math.Abs(pj.X-pi.X) > w {
|
||||
w = math.Abs(pj.X - pi.X)
|
||||
}
|
||||
if math.Abs(pj.Y-pi.Y) > h {
|
||||
h = math.Abs(pj.Y - pi.Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(aligned.Points); i++ {
|
||||
p := aligned.Points[i]
|
||||
shape.AddPoints(p.X, p.Y)
|
||||
}
|
||||
|
||||
collider := resolv.NewObject(aligned.Anchor.X+spaceOffsetX, aligned.Anchor.Y+spaceOffsetY, w, h, tag)
|
||||
collider.SetShape(shape)
|
||||
|
||||
return collider
|
||||
}
|
||||
|
||||
func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.ConvexPolygon) (bool, float64, float64) {
|
||||
origX, origY := playerShape.Position()
|
||||
defer func() {
|
||||
playerShape.SetPosition(origX, origY)
|
||||
}()
|
||||
playerShape.SetPosition(origX+oldDx, origY+oldDy)
|
||||
overlapResult := &SatResult{
|
||||
Overlap: 0,
|
||||
OverlapX: 0,
|
||||
OverlapY: 0,
|
||||
AContainedInB: true,
|
||||
BContainedInA: true,
|
||||
Axis: vector.Vector{0, 0},
|
||||
}
|
||||
if overlapped := IsPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
|
||||
pushbackX, pushbackY := overlapResult.Overlap*overlapResult.OverlapX, overlapResult.Overlap*overlapResult.OverlapY
|
||||
return true, pushbackX, pushbackY
|
||||
} else {
|
||||
return false, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
type SatResult struct {
|
||||
Overlap float64
|
||||
OverlapX float64
|
||||
OverlapY float64
|
||||
AContainedInB bool
|
||||
BContainedInA bool
|
||||
Axis vector.Vector
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
if 1 < aCnt {
|
||||
for _, axis := range a.SATAxes() {
|
||||
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 1 < bCnt {
|
||||
for _, axis := range b.SATAxes() {
|
||||
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, result *SatResult) bool {
|
||||
/*
|
||||
[WARNING] This function is deliberately made private, it shouldn't be used alone (i.e. not along the norms of a polygon), otherwise the pushbacks calculated would be meaningless.
|
||||
|
||||
Consider the following example
|
||||
a: {
|
||||
anchor: [1337.19 1696.74]
|
||||
points: [[0 0] [24 0] [24 24] [0 24]]
|
||||
},
|
||||
b: {
|
||||
anchor: [1277.72 1570.56]
|
||||
points: [[642.57 319.16] [0 319.16] [5.73 0] [643.75 0.90]]
|
||||
}
|
||||
|
||||
e = (-2.98, 1.49).Unit()
|
||||
*/
|
||||
|
||||
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()
|
||||
|
||||
if aStart > dot {
|
||||
aStart = dot
|
||||
}
|
||||
|
||||
if aEnd < dot {
|
||||
aEnd = dot
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range b.Points {
|
||||
dot := (p.X()+b.X)*e.X() + (p.Y()+b.Y)*e.Y()
|
||||
|
||||
if bStart > dot {
|
||||
bStart = dot
|
||||
}
|
||||
|
||||
if bEnd < dot {
|
||||
bEnd = dot
|
||||
}
|
||||
}
|
||||
|
||||
if aStart > bEnd || aEnd < bStart {
|
||||
// Separated by unit vector "e"
|
||||
return true
|
||||
}
|
||||
|
||||
if nil != result {
|
||||
result.Axis = e
|
||||
overlap := float64(0)
|
||||
|
||||
if aStart < bStart {
|
||||
result.AContainedInB = false
|
||||
|
||||
if aEnd < bEnd {
|
||||
overlap = aEnd - bStart
|
||||
result.BContainedInA = false
|
||||
} else {
|
||||
option1 := aEnd - bStart
|
||||
option2 := bEnd - aStart
|
||||
if option1 < option2 {
|
||||
overlap = option1
|
||||
} else {
|
||||
overlap = -option2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.BContainedInA = false
|
||||
|
||||
if aEnd > bEnd {
|
||||
overlap = aStart - bEnd
|
||||
result.AContainedInB = false
|
||||
} else {
|
||||
option1 := aEnd - bStart
|
||||
option2 := bEnd - aStart
|
||||
if option1 < option2 {
|
||||
overlap = option1
|
||||
} else {
|
||||
overlap = -option2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentOverlap := result.Overlap
|
||||
absoluteOverlap := overlap
|
||||
if overlap < 0 {
|
||||
absoluteOverlap = -overlap
|
||||
}
|
||||
|
||||
if 0 == currentOverlap || currentOverlap > absoluteOverlap {
|
||||
var sign float64 = 1
|
||||
if overlap < 0 {
|
||||
sign = -1
|
||||
}
|
||||
|
||||
result.Overlap = absoluteOverlap
|
||||
result.OverlapX = e.X() * sign
|
||||
result.OverlapY = e.Y() * sign
|
||||
}
|
||||
}
|
||||
|
||||
// the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated
|
||||
return false
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package models
|
||||
package dnmshared
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -6,12 +6,9 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ByteArena/box2d"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
. "server/common"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -19,8 +16,7 @@ import (
|
||||
const (
|
||||
LOW_SCORE_TREASURE_TYPE = 1
|
||||
HIGH_SCORE_TREASURE_TYPE = 2
|
||||
|
||||
SPEED_SHOES_TYPE = 3
|
||||
SPEED_SHOES_TYPE = 3
|
||||
|
||||
LOW_SCORE_TREASURE_SCORE = 100
|
||||
HIGH_SCORE_TREASURE_SCORE = 200
|
||||
@@ -179,20 +175,15 @@ func (l *TmxLayer) decodeBase64() ([]uint32, error) {
|
||||
|
||||
type Vec2DList []*Vec2D
|
||||
type Polygon2DList []*Polygon2D
|
||||
type StrToVec2DListMap map[string]*Vec2DList // Note that it's deliberately NOT using "map[string]Vec2DList", for the easy of passing return value to "models/room.go".
|
||||
type StrToPolygon2DListMap map[string]*Polygon2DList // Note that it's deliberately NOT using "map[string]Polygon2DList", for the easy of passing return value to "models/room.go".
|
||||
type StrToVec2DListMap map[string]*Vec2DList
|
||||
type StrToPolygon2DListMap map[string]*Polygon2DList
|
||||
|
||||
func TmxPolylineToPolygon2DInB2World(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) {
|
||||
func tmxPolylineToPolygon2D(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) {
|
||||
if nil == targetPolyline {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
singleValueArray := strings.Split(targetPolyline.Points, " ")
|
||||
pointsCount := len(singleValueArray)
|
||||
|
||||
if pointsCount >= box2d.B2_maxPolygonVertices {
|
||||
return nil, errors.New(fmt.Sprintf("During `TmxPolylineToPolygon2DInB2World`, you have a polygon with pointsCount == %v, exceeding or equal to box2d.B2_maxPolygonVertices == %v, of polyines [%v]", pointsCount, box2d.B2_maxPolygonVertices, singleValueArray))
|
||||
}
|
||||
|
||||
theUntransformedAnchor := &Vec2D{
|
||||
X: singleObjInTmxFile.X,
|
||||
@@ -218,7 +209,6 @@ func TmxPolylineToPolygon2DInB2World(pTmxMapIns *TmxMap, singleObjInTmxFile *Tmx
|
||||
}
|
||||
}
|
||||
|
||||
// Transform to B2World space coordinate.
|
||||
tmp := &Vec2D{
|
||||
X: thePolygon2DFromPolyline.Points[k].X,
|
||||
Y: thePolygon2DFromPolyline.Points[k].Y,
|
||||
@@ -231,7 +221,7 @@ func TmxPolylineToPolygon2DInB2World(pTmxMapIns *TmxMap, singleObjInTmxFile *Tmx
|
||||
return thePolygon2DFromPolyline, nil
|
||||
}
|
||||
|
||||
func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInTsxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline, pTsxIns *Tsx) (*Polygon2D, error) {
|
||||
func tsxPolylineToOffsetsWrtTileCenter(pTmxMapIns *TmxMap, singleObjInTsxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline, pTsxIns *Tsx) (*Polygon2D, error) {
|
||||
if nil == targetPolyline {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -242,10 +232,6 @@ func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInT
|
||||
singleValueArray := strings.Split(targetPolyline.Points, " ")
|
||||
pointsCount := len(singleValueArray)
|
||||
|
||||
if pointsCount >= box2d.B2_maxPolygonVertices {
|
||||
return nil, errors.New(fmt.Sprintf("During `TsxPolylineToOffsetsWrtTileCenterInB2World`, you have a polygon with pointsCount == %v, exceeding or equal to box2d.B2_maxPolygonVertices == %v", pointsCount, box2d.B2_maxPolygonVertices))
|
||||
}
|
||||
|
||||
thePolygon2DFromPolyline := &Polygon2D{
|
||||
Anchor: nil,
|
||||
Points: make([]*Vec2D, pointsCount),
|
||||
@@ -254,7 +240,7 @@ func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInT
|
||||
}
|
||||
|
||||
/*
|
||||
[WARNING] In this case, the "Treasure"s and "GuardTower"s are put into Tmx file as "ImageObject"s, of each the "ProportionalAnchor" is (0.5, 0). Therefore we calculate that "thePolygon2DFromPolyline.Points" are "offsets(in B2World) w.r.t. the BottomCenter". See https://shimo.im/docs/SmLJJhXm2C8XMzZT for details.
|
||||
[WARNING] In this case, the "Treasure"s and "GuardTower"s are put into Tmx file as "ImageObject"s, of each the "ProportionalAnchor" is (0.5, 0). Therefore the "thePolygon2DFromPolyline.Points" are "offsets w.r.t. the BottomCenter". See https://shimo.im/docs/SmLJJhXm2C8XMzZT for details.
|
||||
*/
|
||||
|
||||
for k, value := range singleValueArray {
|
||||
@@ -272,14 +258,12 @@ func TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns *TmxMap, singleObjInT
|
||||
thePolygon2DFromPolyline.Points[k].Y = float64(pTsxIns.TileHeight) - (coordinateValue + offsetFromTopLeftInTileLocalCoordY)
|
||||
}
|
||||
}
|
||||
|
||||
// No need to transform for B2World space coordinate because the marks in a Tsx file is already rectilinear.
|
||||
}
|
||||
|
||||
return thePolygon2DFromPolyline, nil
|
||||
}
|
||||
|
||||
func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, firstGid int, gidBoundariesMapInB2World map[int]StrToPolygon2DListMap) error {
|
||||
func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, firstGid int, gidBoundariesMap map[int]StrToPolygon2DListMap) error {
|
||||
pTsxIns := &Tsx{}
|
||||
err := xml.Unmarshal(byteArrOfTsxFile, pTsxIns)
|
||||
if nil != err {
|
||||
@@ -297,7 +281,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
for _, tile := range pTsxIns.Tiles {
|
||||
globalGid := (firstGid + int(tile.Id))
|
||||
/**
|
||||
Per tile xml str could be
|
||||
A tile xml string could be
|
||||
|
||||
```
|
||||
<tile id="13">
|
||||
@@ -313,7 +297,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
```
|
||||
, we currently REQUIRE that "`an object of a tile` with ONE OR MORE polylines must come with a single corresponding '<property name=`type` value=`...` />', and viceversa".
|
||||
|
||||
Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for how we theoretically fit a "Polyline in Tsx" into a "Polygon2D" and then into the corresponding "B2BodyDef & B2Body in the `world of colliding bodies`".
|
||||
Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for how we theoretically fit a "Polyline in Tsx" into a "Polygon2D".
|
||||
*/
|
||||
|
||||
theObjGroup := tile.ObjectGroup
|
||||
@@ -332,11 +316,11 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
key := singleObj.Properties.Property[0].Value
|
||||
|
||||
var theStrToPolygon2DListMap StrToPolygon2DListMap
|
||||
if existingStrToPolygon2DListMap, ok := gidBoundariesMapInB2World[globalGid]; ok {
|
||||
if existingStrToPolygon2DListMap, ok := gidBoundariesMap[globalGid]; ok {
|
||||
theStrToPolygon2DListMap = existingStrToPolygon2DListMap
|
||||
} else {
|
||||
gidBoundariesMapInB2World[globalGid] = make(StrToPolygon2DListMap, 0)
|
||||
theStrToPolygon2DListMap = gidBoundariesMapInB2World[globalGid]
|
||||
gidBoundariesMap[globalGid] = make(StrToPolygon2DListMap, 0)
|
||||
theStrToPolygon2DListMap = gidBoundariesMap[globalGid]
|
||||
}
|
||||
|
||||
var pThePolygon2DList *Polygon2DList
|
||||
@@ -348,7 +332,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
pThePolygon2DList = theStrToPolygon2DListMap[key]
|
||||
}
|
||||
|
||||
thePolygon2DFromPolyline, err := TsxPolylineToOffsetsWrtTileCenterInB2World(pTmxMapIns, singleObj, singleObj.Polyline, pTsxIns)
|
||||
thePolygon2DFromPolyline, err := tsxPolylineToOffsetsWrtTileCenter(pTmxMapIns, singleObj, singleObj.Polyline, pTsxIns)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
@@ -358,18 +342,9 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[int]StrToPolygon2DListMap) (int32, int32, int32, int32, StrToVec2DListMap, StrToPolygon2DListMap, error) {
|
||||
func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToPolygon2DListMap) (int32, int32, int32, int32, StrToVec2DListMap, StrToPolygon2DListMap, error) {
|
||||
toRetStrToVec2DListMap := make(StrToVec2DListMap, 0)
|
||||
toRetStrToPolygon2DListMap := make(StrToPolygon2DListMap, 0)
|
||||
/*
|
||||
Note that both
|
||||
- "Vec2D"s of "toRetStrToVec2DListMap", and
|
||||
- "Polygon2D"s of "toRetStrToPolygon2DListMap"
|
||||
|
||||
are already transformed into the "coordinate of B2World".
|
||||
|
||||
-- YFLu
|
||||
*/
|
||||
|
||||
for _, objGroup := range pTmxMapIns.ObjectGroups {
|
||||
switch objGroup.Name {
|
||||
@@ -379,10 +354,8 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i
|
||||
if false == ok {
|
||||
theVec2DListToCache := make(Vec2DList, 0)
|
||||
toRetStrToVec2DListMap[objGroup.Name] = &theVec2DListToCache
|
||||
pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name]
|
||||
} else {
|
||||
pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name]
|
||||
}
|
||||
pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name]
|
||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
||||
theUntransformedPos := &Vec2D{
|
||||
X: singleObjInTmxFile.X,
|
||||
@@ -391,22 +364,15 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i
|
||||
thePosInWorld := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedPos)
|
||||
*pTheVec2DListToCache = append(*pTheVec2DListToCache, &thePosInWorld)
|
||||
}
|
||||
case "Pumpkin", "SpeedShoe":
|
||||
case "Barrier":
|
||||
/*
|
||||
Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is located exactly in an overlapping with "Polygon2D.Points[0]" w.r.t. B2World.
|
||||
|
||||
-- YFLu
|
||||
*/
|
||||
// Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]".
|
||||
var pThePolygon2DListToCache *Polygon2DList
|
||||
_, ok := toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
if false == ok {
|
||||
thePolygon2DListToCache := make(Polygon2DList, 0)
|
||||
toRetStrToPolygon2DListMap[objGroup.Name] = &thePolygon2DListToCache
|
||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
} else {
|
||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
}
|
||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
|
||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
||||
if nil == singleObjInTmxFile.Polyline {
|
||||
@@ -416,71 +382,12 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMapInB2World map[i
|
||||
continue
|
||||
}
|
||||
|
||||
thePolygon2DInWorld, err := TmxPolylineToPolygon2DInB2World(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline)
|
||||
thePolygon2DInWorld, err := tmxPolylineToPolygon2D(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
*pThePolygon2DListToCache = append(*pThePolygon2DListToCache, thePolygon2DInWorld)
|
||||
}
|
||||
case "LowScoreTreasure", "GuardTower", "HighScoreTreasure":
|
||||
/*
|
||||
Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" ISN'T located exactly in an overlapping with "Polygon2D.Points[0]" w.r.t. B2World, refer to "https://shimo.im/docs/SmLJJhXm2C8XMzZT" for details.
|
||||
|
||||
-- YFLu
|
||||
*/
|
||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
||||
if nil == singleObjInTmxFile.Gid {
|
||||
continue
|
||||
}
|
||||
theGlobalGid := singleObjInTmxFile.Gid
|
||||
theStrToPolygon2DListMap, ok := gidBoundariesMapInB2World[*theGlobalGid]
|
||||
if false == ok {
|
||||
continue
|
||||
}
|
||||
|
||||
pThePolygon2DList, ok := theStrToPolygon2DListMap[objGroup.Name]
|
||||
if false == ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var pThePolygon2DListToCache *Polygon2DList
|
||||
_, ok = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
if false == ok {
|
||||
thePolygon2DListToCache := make(Polygon2DList, 0)
|
||||
toRetStrToPolygon2DListMap[objGroup.Name] = &thePolygon2DListToCache
|
||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
} else {
|
||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
}
|
||||
|
||||
for _, thePolygon2D := range *pThePolygon2DList {
|
||||
theUntransformedBottomCenterAsAnchor := &Vec2D{
|
||||
X: singleObjInTmxFile.X,
|
||||
Y: singleObjInTmxFile.Y,
|
||||
}
|
||||
|
||||
theTransformedBottomCenterAsAnchor := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedBottomCenterAsAnchor)
|
||||
|
||||
thePolygon2DInWorld := &Polygon2D{
|
||||
Anchor: &theTransformedBottomCenterAsAnchor,
|
||||
Points: make([]*Vec2D, len(thePolygon2D.Points)),
|
||||
TileWidth: thePolygon2D.TileWidth,
|
||||
TileHeight: thePolygon2D.TileHeight,
|
||||
}
|
||||
if nil != singleObjInTmxFile.Width && nil != singleObjInTmxFile.Height {
|
||||
thePolygon2DInWorld.TmxObjectWidth = *singleObjInTmxFile.Width
|
||||
thePolygon2DInWorld.TmxObjectHeight = *singleObjInTmxFile.Height
|
||||
}
|
||||
for kk, p := range thePolygon2D.Points {
|
||||
// [WARNING] It's intentionally recreating a copy of "Vec2D" here.
|
||||
thePolygon2DInWorld.Points[kk] = &Vec2D{
|
||||
X: p.X,
|
||||
Y: p.Y,
|
||||
}
|
||||
}
|
||||
*pThePolygon2DListToCache = append(*pThePolygon2DListToCache, thePolygon2DInWorld)
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -535,3 +442,40 @@ func (pTmxMapIns *TmxMap) continuousObjLayerOffsetToContinuousMapNodePos(continu
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func AlignPolygon2DToBoundingBox(input *Polygon2D) *Polygon2D {
|
||||
// Transform again to put "anchor" at the top-left point of the bounding box for "resolv"
|
||||
float64Max := float64(99999999999999.9)
|
||||
boundingBoxTL := &Vec2D{
|
||||
X: float64Max,
|
||||
Y: float64Max,
|
||||
}
|
||||
for _, p := range input.Points {
|
||||
if p.X < boundingBoxTL.X {
|
||||
boundingBoxTL.X = p.X
|
||||
}
|
||||
if p.Y < boundingBoxTL.Y {
|
||||
boundingBoxTL.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"
|
||||
output := &Polygon2D{
|
||||
Anchor: &Vec2D{
|
||||
X: input.Anchor.X + boundingBoxTL.X,
|
||||
Y: input.Anchor.Y + boundingBoxTL.Y,
|
||||
},
|
||||
Points: make([]*Vec2D, len(input.Points)),
|
||||
TileWidth: input.TileWidth,
|
||||
TileHeight: input.TileHeight,
|
||||
}
|
||||
|
||||
for i, p := range input.Points {
|
||||
output.Points[i] = &Vec2D{
|
||||
X: p.X - boundingBoxTL.X,
|
||||
Y: p.Y - boundingBoxTL.Y,
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
var _ROUTE_PATH;
|
||||
|
||||
function _defineProperty(obj, key, value) {
|
||||
@@ -29,23 +28,6 @@ var constants = {
|
||||
BGM: "BGM"
|
||||
}
|
||||
},
|
||||
PLAYER_NAME: {
|
||||
1: "Merdan",
|
||||
2: "Monroe",
|
||||
},
|
||||
SOCKET_EVENT: {
|
||||
CONTROL: "control",
|
||||
SYNC: "sync",
|
||||
LOGIN: "login",
|
||||
CREATE: "create"
|
||||
},
|
||||
WECHAT: {
|
||||
AUTHORIZE_PATH: "/connect/oauth2/authorize",
|
||||
REDIRECT_RUI_KEY: "redirect_uri=",
|
||||
RESPONSE_TYPE: "response_type=code",
|
||||
SCOPE: "scope=snsapi_userinfo",
|
||||
FIN: "#wechat_redirect"
|
||||
},
|
||||
ROUTE_PATH: (_ROUTE_PATH = {
|
||||
PLAYER: "/player",
|
||||
JSCONFIG: "/jsconfig",
|
||||
@@ -61,8 +43,6 @@ var constants = {
|
||||
LIST: "/list",
|
||||
READ: "/read",
|
||||
PROFILE: "/profile",
|
||||
WECHAT: "/wechat",
|
||||
WECHATGAME: "/wechatGame",
|
||||
FETCH: "/fetch",
|
||||
}, _defineProperty(_ROUTE_PATH, "LOGIN", "/login"), _defineProperty(_ROUTE_PATH, "RET_CODE", "/retCode"), _defineProperty(_ROUTE_PATH, "REGEX", "/regex"), _defineProperty(_ROUTE_PATH, "SMS_CAPTCHA", "/SmsCaptcha"), _defineProperty(_ROUTE_PATH, "GET", "/get"), _ROUTE_PATH),
|
||||
REQUEST_QUERY: {
|
||||
@@ -138,7 +118,6 @@ var constants = {
|
||||
INCORRECT_PHONE_NUMBER: '手机号不正确',
|
||||
LOG_OUT: '您已在其他地方登陆',
|
||||
GAME_OVER: '游戏结束,您的得分是',
|
||||
WECHAT_LOGIN_FAILS: "微信登录失败",
|
||||
},
|
||||
CONFIRM_BUTTON_LABEL: {
|
||||
RESTART: '重新开始'
|
||||
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "51b3303a-7c55-4f8b-b6b9-b5efb6164d19",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "8347ba4a-e73c-4173-a9ba-f7711fae5a90",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "05720598-8487-406c-b2f3-2059240fde56",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.2",
|
||||
"uuid": "4e2296fe-8855-4fb4-a407-fea295ded82e",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "da664a14-58c3-4f57-8aca-1270f96bf3ee",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "59b65107-0da7-47b3-a08d-7de824dd5a39",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,335 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="isometric" renderorder="right-down" width="50" height="50" tilewidth="64" tileheight="64" infinite="0" nextlayerid="11" nextobjectid="213">
|
||||
<tileset firstgid="1" source="Tile_W64_H64_S01.tsx"/>
|
||||
<tileset firstgid="17" source="Tile_W300_H300_S01.tsx"/>
|
||||
<layer id="1" name="GroundFloor" width="50" height="50">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJztz0ENACAMALGR4F8zNspyjwronZm7xPlcD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPy7bHBg/ldQwR
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="PlayerStartingPos">
|
||||
<object id="135" x="320" y="2884">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="137" x="2876" y="320">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<layer id="3" name="FirsrtFloor" width="50" height="50">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJztWctuBCEMW7Vqt9v2/7+32gMSQnnYTmB6WB+ZwZmEkHHgdnuBxe8/5WLwcyHXuzH2ccAuw5Wty3j/bjyzxlC7M9iYrFxZfNbnqi/IOqAxqfow8AWOoXZmZL58k9xvzrg1L+JS9oO6LijfCR882yvWdUH5rG+KuBgfrFo42+7CJ/m+l5MWoloYjZ+CUsN2+OLVc0YDRPa9nNzhC7LPs//Xo8FuNs5wRvt2Rw7v8AXZ5zty2FvL3Xsf4e+qsVf60l1jq754MR2w8qFSY6MaqdSRJ7KYRnNWIL509iseZ4de93TyHZirwOOM1lXtC6JnSg+K2FPnVHSysr9P+4Dq8a5+Wp2jcHq5FPWgFXuZXu/sqxCuHX1cR+1BtN4A0y96/ycldiu8XOquxWhNOZ1LDFA+RCdn/4OOeFjw9nLl/5TVUPZ8YIX3bSd6z26w33zKl0xzM/xd2hvhnKFo7ox/h/ZmtOcpXzp1q6K5PXjfjPSAKJcF9jwXQdd9B8q1E8pZYUW3zlBqVYSOPRatm1XjKrUqQsUXties1qqs9kd8im5l7ovQnOzYr0wuWc+YOz7kvcq6ILkU9ZOqhmfvdj17M6rn3ayGV30YUM8qB6qxeIK9n96FaixmXOVDJ3bomRc4/AGscghn
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="7" name="HighScoreTreasure">
|
||||
<object id="172" gid="16" x="1736" y="708" width="64" height="64"/>
|
||||
<object id="173" gid="16" x="2284" y="768" width="64" height="64"/>
|
||||
<object id="170" gid="16" x="916" y="1608" width="64" height="64"/>
|
||||
<object id="171" gid="16" x="1166" y="2674" width="64" height="64"/>
|
||||
<object id="199" gid="16" x="2536.36" y="2533.7" width="64" height="64"/>
|
||||
<object id="200" gid="16" x="2812.12" y="3045.82" width="64" height="64"/>
|
||||
<object id="201" gid="16" x="3033.33" y="2824.61" width="64" height="64"/>
|
||||
<object id="202" gid="16" x="2093.94" y="1467.03" width="64" height="64"/>
|
||||
<object id="203" gid="16" x="654.545" y="664" width="64" height="64"/>
|
||||
<object id="204" gid="16" x="172.727" y="376.121" width="64" height="64"/>
|
||||
<object id="205" gid="16" x="360.606" y="176.121" width="64" height="64"/>
|
||||
</objectgroup>
|
||||
<objectgroup id="4" name="Barrier">
|
||||
<properties>
|
||||
<property name="type" value="barrier_and_shelter"/>
|
||||
</properties>
|
||||
<object id="1" x="234" y="730">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -74,78 178,330 250,258"/>
|
||||
</object>
|
||||
<object id="2" x="804" y="156">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -74,78 178,330 250,258"/>
|
||||
</object>
|
||||
<object id="3" x="230" y="410">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="250,-258 -74,78 178,330 504,0"/>
|
||||
</object>
|
||||
<object id="4" x="2470" y="2650">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="250,-258 -74,78 178,330 504,0"/>
|
||||
</object>
|
||||
<object id="5" x="1082.23" y="1537.08">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="548.339,-547.082 -94.2284,95.4898 230.657,408.918 867.772,-230"/>
|
||||
</object>
|
||||
<object id="6" x="1188" y="604">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -74,78 178,330 250,258"/>
|
||||
</object>
|
||||
<object id="7" x="889.741" y="770">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,22 -93.7407,98.1818 283.593,478 358.259,416.909"/>
|
||||
</object>
|
||||
<object id="8" x="691.741" y="1088">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-18,30 -93.7407,98.1818 169.593,356 238.259,288.909"/>
|
||||
</object>
|
||||
<object id="9" x="311.741" y="1916">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-22,30 -96.4077,103.515 867.593,1062 938.259,992.909"/>
|
||||
</object>
|
||||
<object id="10" x="629.741" y="1854">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-22,30 -93.7407,98.1818 361.593,548 430.259,480.909"/>
|
||||
</object>
|
||||
<object id="11" x="1015.74" y="1852">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 329.593,512 396.259,450.909"/>
|
||||
</object>
|
||||
<object id="12" x="1973.74" y="514">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 355.593,538 424.259,474.909"/>
|
||||
</object>
|
||||
<object id="13" x="2041.74" y="194">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 865.593,1048 934.259,992.909"/>
|
||||
</object>
|
||||
<object id="14" x="1975.74" y="896">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 317.593,508 382.259,440.909"/>
|
||||
</object>
|
||||
<object id="15" x="1917.74" y="1798">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 285.593,472 352.259,402.909"/>
|
||||
</object>
|
||||
<object id="16" x="1399.74" y="2564">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 228.259,278.909"/>
|
||||
</object>
|
||||
<object id="17" x="1595.74" y="2372">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="18" x="1791.74" y="2184">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="19" x="2301.74" y="1670">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="20" x="2489.74" y="1478">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="21" x="2683.74" y="1284">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="22" x="2109.74" y="2690">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="23" x="2809.74" y="1986">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-26,26 -93.7407,98.1818 161.593,348 226.259,280.909"/>
|
||||
</object>
|
||||
<object id="41" x="1069.7" y="415.152">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -66.6667,-72.7273 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="42" x="684.848" y="793.939">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -66.6667,-72.7273 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="43" x="360.606" y="1560.61">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="381.818,-375.758 309.091,-442.424 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="44" x="1445.45" y="475.758">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="381.818,-375.758 309.091,-442.424 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="45" x="354.545" y="2778.79">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
<property name="debug_mark" value="1"/>
|
||||
</properties>
|
||||
<polyline points="123.031,-135.636 67.6364,-192.909 -323.636,198.303 -258.667,265.939"/>
|
||||
</object>
|
||||
<object id="46" x="481.818" y="2906.06">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="136.364,-130.303 63.6364,-190.909 -330.636,202.637 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="47" x="2915.15" y="224.242">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="136.364,-130.303 63.6364,-190.909 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="48" x="3048.48" y="351.515">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="136.364,-130.303 63.6364,-190.909 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="49" x="869.697" y="1754.55">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-3.0303,-3.0303 -66.6667,-66.6667 -330.303,204.97 -258.667,273.939"/>
|
||||
</object>
|
||||
<object id="50" x="2021.21" y="609.091">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="-3.0303,-3.0303 -66.6667,-66.6667 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="51" x="2406.06" y="1309.09">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="118.182,-124.242 57.5758,-184.848 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="52" x="1454.55" y="2266.67">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="118.182,-124.242 57.5758,-184.848 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="53" x="1818.18" y="2648.48">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="200,-193.939 133.333,-260.606 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="54" x="2718.18" y="1754.55">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="200,-193.939 133.333,-260.606 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="55" x="2342.42" y="2596.97">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="60.6061,-72.7273 3.0303,-136.364 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="56" x="2793.94" y="2151.52">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="60.6061,-72.7273 3.0303,-136.364 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="57" x="69.697" y="57.5758">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -78.7879,-1.27898e-13 -66.6667,3121.21 1.13687e-13,3121.21"/>
|
||||
</object>
|
||||
<object id="59" x="3200" y="66.6667">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -6.06061,-78.7879 -3215.15,-81.8182 -3221.21,9.09091"/>
|
||||
</object>
|
||||
<object id="60" x="3203.03" y="3221.21">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -6.06061,-78.7879 -3215.15,-81.8182 -3221.21,9.09091"/>
|
||||
</object>
|
||||
<object id="61" x="3209.09" y="27.2727">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -78.7879,-1.27898e-13 -66.6667,3121.21 1.13687e-13,3121.21"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup id="5" name="LowScoreTreasure">
|
||||
<object id="165" gid="13" x="1520" y="204" width="64" height="64" visible="0"/>
|
||||
<object id="166" gid="13" x="1372" y="352" width="64" height="64" visible="0"/>
|
||||
<object id="167" gid="13" x="1184" y="524" width="64" height="64" visible="0"/>
|
||||
<object id="168" gid="13" x="544" y="1184" width="64" height="64" visible="0"/>
|
||||
<object id="169" gid="13" x="294" y="1442" width="64" height="64" visible="0"/>
|
||||
<object id="174" gid="16" x="2750" y="1234" width="64" height="64" visible="0"/>
|
||||
<object id="175" gid="13" x="1562" y="1990" width="64" height="64" visible="0"/>
|
||||
<object id="176" gid="13" x="1846" y="1718" width="64" height="64" visible="0"/>
|
||||
<object id="177" gid="13" x="906" y="2438" width="64" height="64" visible="0"/>
|
||||
<object id="178" gid="13" x="638" y="2186" width="64" height="64" visible="0"/>
|
||||
<object id="179" gid="13" x="378" y="1878" width="64" height="64" visible="0"/>
|
||||
<object id="180" gid="13" x="580" y="1672" width="64" height="64" visible="0"/>
|
||||
<object id="181" gid="13" x="1518" y="634" width="64" height="64" visible="0"/>
|
||||
<object id="182" gid="13" x="1818" y="410" width="64" height="64" visible="0"/>
|
||||
<object id="183" gid="13" x="2308" y="360" width="64" height="64" visible="0"/>
|
||||
<object id="184" gid="13" x="2524" y="576" width="64" height="64" visible="0"/>
|
||||
<object id="186" gid="13" x="2726" y="790" width="64" height="64" visible="0"/>
|
||||
<object id="187" gid="13" x="2928" y="972" width="64" height="64" visible="0"/>
|
||||
<object id="192" gid="13" x="1484.85" y="3064" width="64" height="64" visible="0"/>
|
||||
<object id="193" gid="13" x="1972.73" y="3048.85" width="64" height="64" visible="0"/>
|
||||
<object id="194" gid="13" x="2006.06" y="2664" width="64" height="64" visible="0"/>
|
||||
<object id="195" gid="13" x="312.121" y="2291.27" width="64" height="64" visible="0"/>
|
||||
<object id="196" gid="13" x="503.03" y="2488.24" width="64" height="64" visible="0"/>
|
||||
<object id="197" gid="13" x="606.061" y="3076.12" width="64" height="64" visible="0"/>
|
||||
<object id="198" gid="13" x="833.333" y="2842.79" width="64" height="64" visible="0"/>
|
||||
<object id="206" gid="13" x="2612.12" y="2064" width="64" height="64" visible="0"/>
|
||||
<object id="207" gid="13" x="3030.3" y="1985.21" width="64" height="64" visible="0"/>
|
||||
</objectgroup>
|
||||
<objectgroup id="6" name="GuardTower">
|
||||
<object id="188" gid="17" x="1429.33" y="1781.33" width="300" height="300" visible="0"/>
|
||||
<object id="210" gid="17" x="1784.67" y="1414" width="300" height="300"/>
|
||||
<object id="211" gid="17" x="2786" y="2783.33" width="300" height="300"/>
|
||||
<object id="212" gid="17" x="532.667" y="543.333" width="300" height="300"/>
|
||||
</objectgroup>
|
||||
</map>
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.0.2",
|
||||
"uuid": "7fd0b77d-0736-4e00-89eb-7111f07ed4f1",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="isometric" renderorder="right-down" width="50" height="50" tilewidth="64" tileheight="64" infinite="0" nextlayerid="11" nextobjectid="213">
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="isometric" renderorder="right-down" width="50" height="50" tilewidth="64" tileheight="64" infinite="0" nextlayerid="11" nextobjectid="218">
|
||||
<tileset firstgid="1" source="Tile_W64_H64_S01.tsx"/>
|
||||
<tileset firstgid="17" source="Tile_W300_H300_S01.tsx"/>
|
||||
<layer id="1" name="GroundFloor" width="50" height="50" locked="1">
|
||||
@@ -33,7 +33,7 @@
|
||||
<object id="204" gid="16" x="172.727" y="376.121" width="64" height="64"/>
|
||||
<object id="205" gid="16" x="360.606" y="176.121" width="64" height="64"/>
|
||||
</objectgroup>
|
||||
<objectgroup id="4" name="Barrier" locked="1">
|
||||
<objectgroup id="4" name="Barrier">
|
||||
<properties>
|
||||
<property name="type" value="barrier_and_shelter"/>
|
||||
</properties>
|
||||
@@ -271,29 +271,29 @@
|
||||
</properties>
|
||||
<polyline points="60.6061,-72.7273 3.0303,-136.364 -330.303,196.97 -266.667,260.606"/>
|
||||
</object>
|
||||
<object id="57" x="69.697" y="57.5758">
|
||||
<object id="213" x="1854.55" y="-1351.52">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -78.7879,-1.27898e-13 -66.6667,3121.21 1.13687e-13,3121.21"/>
|
||||
<polyline points="0,0 -3190.91,3215.15 -3115.15,3290.91 48.4848,54.5455"/>
|
||||
</object>
|
||||
<object id="59" x="3200" y="66.6667">
|
||||
<object id="214" x="-572.727" y="1257.58">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -6.06061,-78.7879 -3215.15,-81.8182 -3221.21,9.09091"/>
|
||||
<polyline points="0,0 2575.76,2624.24 2472.73,2727.27 -136.364,112.121"/>
|
||||
</object>
|
||||
<object id="60" x="3203.03" y="3221.21">
|
||||
<object id="216" x="1190.91" y="-584.848">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -6.06061,-78.7879 -3215.15,-81.8182 -3221.21,9.09091"/>
|
||||
<polyline points="0,0 2657.58,2627.27 2818.18,2466.67 172.727,-166.667"/>
|
||||
</object>
|
||||
<object id="61" x="3209.09" y="27.2727">
|
||||
<object id="217" x="1887.88" y="3748.48">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="0,0 -78.7879,-1.27898e-13 -66.6667,3121.21 1.13687e-13,3121.21"/>
|
||||
<polyline points="0,0 221.212,227.273 2087.88,-1627.27 1842.42,-1872.73"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup id="5" name="LowScoreTreasure">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "33d33d2f-5ca7-4677-9c82-4ced71aa0f8a",
|
||||
"uuid": "6955a517-3fb6-4777-b8b0-74dbd76f18e4",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "f9460fe9-26ad-4e4b-8a3c-c97bef705a71",
|
||||
"uuid": "51c54820-d753-4be8-a855-5760eed8f7ef",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "b711d3f8-b9f4-41ab-a7e4-6562992fb65e",
|
||||
"uuid": "136d09e9-c33c-45dc-abb7-e367d730c814",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
@@ -11,8 +11,8 @@
|
||||
"subMetas": {
|
||||
"Tile_W256_H128_S01": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "2d6c9481-6bd5-4c19-b468-529d027226c3",
|
||||
"rawTextureUuid": "b711d3f8-b9f4-41ab-a7e4-6562992fb65e",
|
||||
"uuid": "7acc48f5-d9c9-4438-8794-57a85590bd97",
|
||||
"rawTextureUuid": "136d09e9-c33c-45dc-abb7-e367d730c814",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "df775ad6-885e-411b-8b2a-f4bcf70b4fbf",
|
||||
"subMetas": {}
|
||||
}
|
Before Width: | Height: | Size: 229 KiB After Width: | Height: | Size: 229 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "757f31be-7ad1-42dc-bd6b-2b4c7652e457",
|
||||
"uuid": "d8e6c175-1f17-48df-a0aa-cdd9785f4d3a",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
@@ -11,8 +11,8 @@
|
||||
"subMetas": {
|
||||
"Tile_W256_H256_S01": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "0d9aafd3-d738-473c-95b8-bf577b78f03d",
|
||||
"rawTextureUuid": "757f31be-7ad1-42dc-bd6b-2b4c7652e457",
|
||||
"uuid": "4a23290b-bf5a-4849-ac19-6ebd4b7daa59",
|
||||
"rawTextureUuid": "d8e6c175-1f17-48df-a0aa-cdd9785f4d3a",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "81508f64-031d-4d00-9aa0-8e9841907d0a",
|
||||
"subMetas": {}
|
||||
}
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "2385ca17-af24-4122-a271-785f3010d7f2",
|
||||
"uuid": "74245e28-6cec-4960-ac41-5b482ad8fd13",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
@@ -11,8 +11,8 @@
|
||||
"subMetas": {
|
||||
"Tile_W256_H256_S02": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "34e3f356-e65d-4745-8f70-7706aa4083f8",
|
||||
"rawTextureUuid": "2385ca17-af24-4122-a271-785f3010d7f2",
|
||||
"uuid": "8fc46c1f-6fb4-4290-99f3-b773b92312b7",
|
||||
"rawTextureUuid": "74245e28-6cec-4960-ac41-5b482ad8fd13",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "4e822a8b-f3be-4b83-b61d-9e04c56c5eba",
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.2",
|
||||
"uuid": "a9a02975-8df5-42a1-bc25-b0ff7c1c03ba",
|
||||
"subMetas": {}
|
||||
}
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "0a5e9b39-6a98-4b45-9ad5-6df3effec2ef",
|
||||
"uuid": "c30bd4d7-efdc-410c-8bdf-4a3dfc77bebd",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
@@ -11,8 +11,8 @@
|
||||
"subMetas": {
|
||||
"Tile_W300_H300_S01": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "acb30663-c0cf-4727-a046-26e40610c49f",
|
||||
"rawTextureUuid": "0a5e9b39-6a98-4b45-9ad5-6df3effec2ef",
|
||||
"uuid": "66b49304-7b5b-442c-92a5-d2b368abf659",
|
||||
"rawTextureUuid": "c30bd4d7-efdc-410c-8bdf-4a3dfc77bebd",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "8c8beea4-faa3-4270-aa27-dc5f2b7766c2",
|
||||
"subMetas": {}
|
||||
}
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "2.3.3",
|
||||
"uuid": "5e68ce04-f41f-4ab0-a55c-608542e5638a",
|
||||
"uuid": "dd454e0f-4474-4801-8e86-ba134f6293a9",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
@@ -11,8 +11,8 @@
|
||||
"subMetas": {
|
||||
"Tile_W64_H64_S01": {
|
||||
"ver": "1.0.4",
|
||||
"uuid": "610a5bd5-c643-426e-a6e8-63acc5c516d9",
|
||||
"rawTextureUuid": "5e68ce04-f41f-4ab0-a55c-608542e5638a",
|
||||
"uuid": "e287ce95-457a-48b3-9c94-314bbcb69009",
|
||||
"rawTextureUuid": "dd454e0f-4474-4801-8e86-ba134f6293a9",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.0",
|
||||
"uuid": "c63de1bc-6d0e-467e-848b-f5c021a1b950",
|
||||
"subMetas": {}
|
||||
}
|
40
frontend/assets/resources/map/simple/map.tmx
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="isometric" renderorder="right-down" width="50" height="50" tilewidth="64" tileheight="64" infinite="0" nextlayerid="11" nextobjectid="214">
|
||||
<tileset firstgid="1" source="Tile_W64_H64_S01.tsx"/>
|
||||
<tileset firstgid="17" source="Tile_W300_H300_S01.tsx"/>
|
||||
<layer id="1" name="GroundFloor" width="50" height="50" locked="1">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJztz0ENACAMALGR4F8zNspyjwronZm7xPlcD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPSw9LD0sPy7bHBg/ldQwR
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="PlayerStartingPos">
|
||||
<object id="135" x="1442.33" y="2063">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="137" x="2270" y="1640">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<layer id="3" name="FirsrtFloor" width="50" height="50">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJztwQENAAAAwqD3T20ON6AAAAAAAAAAAADg3wAnEAAB
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="4" name="Barrier">
|
||||
<properties>
|
||||
<property name="type" value="barrier_and_shelter"/>
|
||||
</properties>
|
||||
<object id="5" x="1082.23" y="1537.08">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="548.339,-547.082 -94.2284,95.4898 230.657,408.918 867.772,-230"/>
|
||||
</object>
|
||||
<object id="213" x="1044" y="1852">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
<polyline points="1101.33,-342 470.926,284.848 526.26,339.333 1152.93,-285.091"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
5
frontend/assets/resources/map/simple/map.tmx.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.0.2",
|
||||
"uuid": "9b8777b4-8725-46ea-96c0-d580e9f023d1",
|
||||
"subMetas": {}
|
||||
}
|
@@ -27,17 +27,28 @@ message Polygon2DList {
|
||||
}
|
||||
|
||||
message BattleColliderInfo {
|
||||
int32 intervalToPing = 1;
|
||||
int32 willKickIfInactiveFor = 2;
|
||||
int32 boundRoomId = 3;
|
||||
string stageName = 1;
|
||||
map<string, Vec2DList> strToVec2DListMap = 2;
|
||||
map<string, Polygon2DList> strToPolygon2DListMap = 3;
|
||||
int32 stageDiscreteW = 4;
|
||||
int32 stageDiscreteH = 5;
|
||||
int32 stageTileW = 6;
|
||||
int32 stageTileH = 7;
|
||||
|
||||
string stageName = 4;
|
||||
map<string, Vec2DList> strToVec2DListMap = 5;
|
||||
map<string, Polygon2DList> strToPolygon2DListMap = 6;
|
||||
int32 StageDiscreteW = 7;
|
||||
int32 StageDiscreteH = 8;
|
||||
int32 StageTileW = 9;
|
||||
int32 StageTileH = 10;
|
||||
int32 intervalToPing = 8;
|
||||
int32 willKickIfInactiveFor = 9;
|
||||
int32 boundRoomId = 10;
|
||||
int64 battleDurationNanos = 11;
|
||||
int32 serverFps = 12;
|
||||
int32 inputDelayFrames = 13;
|
||||
uint32 inputScaleFrames = 14;
|
||||
int32 nstDelayFrames = 15;
|
||||
int32 inputFrameUpsyncDelayTolerance = 16;
|
||||
int32 maxChasingRenderFramesPerUpdate = 17;
|
||||
int32 playerBattleState = 18;
|
||||
double rollbackEstimatedDt = 19;
|
||||
double rollbackEstimatedDtMillis = 20;
|
||||
int64 rollbackEstimatedDtNanos = 21;
|
||||
}
|
||||
|
||||
message Player {
|
||||
@@ -45,7 +56,7 @@ message Player {
|
||||
double x = 2;
|
||||
double y = 3;
|
||||
Direction dir = 4;
|
||||
int32 speed = 5;
|
||||
double speed = 5;
|
||||
int32 battleState = 6;
|
||||
int32 lastMoveGmtMillis = 7;
|
||||
int32 score = 10;
|
||||
@@ -61,76 +72,6 @@ message PlayerMeta {
|
||||
int32 joinIndex = 5;
|
||||
}
|
||||
|
||||
message Treasure {
|
||||
int32 id = 1;
|
||||
int32 localIdInBattle = 2;
|
||||
int32 score = 3;
|
||||
double x = 4;
|
||||
double y = 5;
|
||||
bool removed = 6;
|
||||
int32 type = 7;
|
||||
}
|
||||
|
||||
message Bullet {
|
||||
int32 localIdInBattle = 1;
|
||||
double linearSpeed = 2;
|
||||
double x = 3;
|
||||
double y = 4;
|
||||
bool removed = 5;
|
||||
Vec2D startAtPoint = 6;
|
||||
Vec2D endAtPoint = 7;
|
||||
}
|
||||
|
||||
message Trap {
|
||||
int32 id = 1;
|
||||
int32 localIdInBattle = 2;
|
||||
int32 type = 3;
|
||||
double x = 4;
|
||||
double y = 5;
|
||||
bool removed = 6;
|
||||
}
|
||||
|
||||
message SpeedShoe {
|
||||
int32 id = 1;
|
||||
int32 localIdInBattle = 2;
|
||||
double x = 3;
|
||||
double y = 4;
|
||||
bool removed = 5;
|
||||
int32 type = 6;
|
||||
}
|
||||
|
||||
message Pumpkin {
|
||||
int32 localIdInBattle = 1;
|
||||
double linearSpeed = 2;
|
||||
double x = 3;
|
||||
double y = 4;
|
||||
bool removed = 5;
|
||||
}
|
||||
|
||||
message GuardTower {
|
||||
int32 id = 1;
|
||||
int32 localIdInBattle = 2;
|
||||
int32 type = 3;
|
||||
double x = 4;
|
||||
double y = 5;
|
||||
bool removed = 6;
|
||||
}
|
||||
|
||||
message RoomDownsyncFrame {
|
||||
int32 id = 1;
|
||||
int32 refFrameId = 2;
|
||||
map<int32, Player> players = 3;
|
||||
int64 sentAt = 4;
|
||||
int64 countdownNanos = 5;
|
||||
map<int32, Treasure> treasures = 6;
|
||||
map<int32, Trap> traps = 7;
|
||||
map<int32, Bullet> bullets = 8;
|
||||
map<int32, SpeedShoe> speedShoes = 9;
|
||||
map<int32, Pumpkin> pumpkin = 10;
|
||||
map<int32, GuardTower> guardTowers = 11;
|
||||
map<int32, PlayerMeta> playerMetas = 12;
|
||||
}
|
||||
|
||||
message InputFrameUpsync {
|
||||
int32 inputFrameId = 1;
|
||||
int32 encodedDir = 6;
|
||||
@@ -146,6 +87,13 @@ message HeartbeatUpsync {
|
||||
int64 clientTimestamp = 1;
|
||||
}
|
||||
|
||||
message RoomDownsyncFrame {
|
||||
int32 id = 1;
|
||||
map<int32, Player> players = 2;
|
||||
int64 countdownNanos = 3;
|
||||
map<int32, PlayerMeta> playerMetas = 4;
|
||||
}
|
||||
|
||||
message WsReq {
|
||||
int32 msgId = 1;
|
||||
int32 playerId = 2;
|
||||
|
@@ -8,7 +8,8 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"asyncLoadAssets": false
|
||||
"asyncLoadAssets": false,
|
||||
"readonly": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
@@ -27,7 +28,6 @@
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_level": 1,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 11
|
||||
@@ -63,17 +63,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 2,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -89,7 +78,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 2,
|
||||
"groupIndex": 2,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
@@ -100,7 +101,6 @@
|
||||
},
|
||||
"_children": [],
|
||||
"_active": false,
|
||||
"_level": 0,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
@@ -127,17 +127,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -153,7 +142,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
@@ -163,6 +164,7 @@
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
"_useOriginalSize": false,
|
||||
"_string": "(0, 0)",
|
||||
"_N$string": "(0, 0)",
|
||||
@@ -200,7 +202,6 @@
|
||||
},
|
||||
"_children": [],
|
||||
"_active": false,
|
||||
"_level": 2,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 6
|
||||
@@ -227,17 +228,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -253,7 +243,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ParticleSystem",
|
||||
@@ -263,6 +265,9 @@
|
||||
"__id__": 5
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 1,
|
||||
"_custom": true,
|
||||
"_file": {
|
||||
"__uuid__": "b2687ac4-099e-403c-a192-ff477686f4f5"
|
||||
@@ -271,8 +276,6 @@
|
||||
"__uuid__": "472df5d3-35e7-4184-9e6c-7f41bee65ee3"
|
||||
},
|
||||
"_texture": null,
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 1,
|
||||
"_stopped": false,
|
||||
"playOnLoad": true,
|
||||
"autoRemoveOnFinish": false,
|
||||
@@ -329,6 +332,7 @@
|
||||
"x": 7,
|
||||
"y": 7
|
||||
},
|
||||
"_positionType": 1,
|
||||
"positionType": 1,
|
||||
"emitterMode": 0,
|
||||
"gravity": {
|
||||
@@ -372,7 +376,6 @@
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_level": 2,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
@@ -399,17 +402,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -425,7 +417,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
@@ -435,6 +439,13 @@
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||
}
|
||||
],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "a2170e4c-df31-41ef-be73-f4f605e75821"
|
||||
},
|
||||
@@ -449,12 +460,9 @@
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_state": 0,
|
||||
"_atlas": {
|
||||
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
|
||||
},
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
@@ -476,6 +484,9 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": null,
|
||||
"_type": 0,
|
||||
"_sizeMode": 0,
|
||||
@@ -488,10 +499,7 @@
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_state": 0,
|
||||
"_atlas": null,
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
@@ -549,8 +557,8 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"animComp": null,
|
||||
"baseSpeed": 300,
|
||||
"speed": 200,
|
||||
"baseSpeed": 50,
|
||||
"speed": 50,
|
||||
"lastMovedAt": 0,
|
||||
"eps": 0.1,
|
||||
"magicLeanLowerBound": 0.414,
|
||||
|
@@ -8,7 +8,8 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"asyncLoadAssets": false
|
||||
"asyncLoadAssets": false,
|
||||
"readonly": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
@@ -27,7 +28,6 @@
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_level": 1,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 11
|
||||
@@ -63,17 +63,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 2,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -89,7 +78,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 2,
|
||||
"groupIndex": 2,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
@@ -100,7 +101,6 @@
|
||||
},
|
||||
"_children": [],
|
||||
"_active": false,
|
||||
"_level": 0,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
@@ -127,17 +127,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -153,7 +142,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
@@ -163,6 +164,7 @@
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
"_useOriginalSize": false,
|
||||
"_string": "(0, 0)",
|
||||
"_N$string": "(0, 0)",
|
||||
@@ -200,7 +202,6 @@
|
||||
},
|
||||
"_children": [],
|
||||
"_active": false,
|
||||
"_level": 2,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 6
|
||||
@@ -227,17 +228,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -253,7 +243,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ParticleSystem",
|
||||
@@ -263,6 +265,9 @@
|
||||
"__id__": 5
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 1,
|
||||
"_custom": true,
|
||||
"_file": {
|
||||
"__uuid__": "b2687ac4-099e-403c-a192-ff477686f4f5"
|
||||
@@ -271,8 +276,6 @@
|
||||
"__uuid__": "472df5d3-35e7-4184-9e6c-7f41bee65ee3"
|
||||
},
|
||||
"_texture": null,
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 1,
|
||||
"_stopped": false,
|
||||
"playOnLoad": true,
|
||||
"autoRemoveOnFinish": false,
|
||||
@@ -329,6 +332,7 @@
|
||||
"x": 7,
|
||||
"y": 7
|
||||
},
|
||||
"_positionType": 1,
|
||||
"positionType": 1,
|
||||
"emitterMode": 0,
|
||||
"gravity": {
|
||||
@@ -372,7 +376,6 @@
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_level": 2,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
@@ -399,17 +402,6 @@
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_quat": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": "",
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
@@ -425,7 +417,19 @@
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
@@ -435,6 +439,13 @@
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||
}
|
||||
],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "a2170e4c-df31-41ef-be73-f4f605e75821"
|
||||
},
|
||||
@@ -449,12 +460,9 @@
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_state": 0,
|
||||
"_atlas": {
|
||||
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
|
||||
},
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
@@ -476,6 +484,9 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": null,
|
||||
"_type": 0,
|
||||
"_sizeMode": 0,
|
||||
@@ -488,10 +499,7 @@
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_state": 0,
|
||||
"_atlas": null,
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
@@ -549,8 +557,8 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"animComp": null,
|
||||
"baseSpeed": 300,
|
||||
"speed": 200,
|
||||
"baseSpeed": 50,
|
||||
"speed": 50,
|
||||
"lastMovedAt": 0,
|
||||
"eps": 0.1,
|
||||
"magicLeanLowerBound": 0.414,
|
||||
|
@@ -304,7 +304,6 @@
|
||||
"__id__": 5
|
||||
},
|
||||
"_enabled": true,
|
||||
"useDiffFrameAlgo": true,
|
||||
"canvasNode": {
|
||||
"__id__": 2
|
||||
},
|
||||
@@ -317,22 +316,9 @@
|
||||
"player2Prefab": {
|
||||
"__uuid__": "1f479636-9eb8-4612-8f97-371964d6eae3"
|
||||
},
|
||||
"treasurePrefab": {
|
||||
"__uuid__": "ec3f3234-9b84-43c2-a3cd-58b924cce8e5"
|
||||
},
|
||||
"trapPrefab": {
|
||||
"__uuid__": "9f340a31-ddfa-46c2-94c7-d11615aedcb1"
|
||||
},
|
||||
"speedShoePrefab": null,
|
||||
"polygonBoundaryBarrierPrefab": {
|
||||
"__uuid__": "4154eec0-d644-482f-a889-c00ae6b69958"
|
||||
},
|
||||
"polygonBoundaryShelterPrefab": {
|
||||
"__uuid__": "f820a6ec-e7a9-46cf-9b8a-331aa3e21487"
|
||||
},
|
||||
"polygonBoundaryShelterZReducerPrefab": {
|
||||
"__uuid__": "a36d024b-a979-4d18-b089-19af313ffb82"
|
||||
},
|
||||
"keyboardInputControllerNode": {
|
||||
"__id__": 8
|
||||
},
|
||||
@@ -351,9 +337,6 @@
|
||||
"countdownLabel": {
|
||||
"__id__": 30
|
||||
},
|
||||
"trapBulletPrefab": {
|
||||
"__uuid__": "7673e0e4-bebd-4caa-8a10-a6e1e86f1b2f"
|
||||
},
|
||||
"resultPanelPrefab": {
|
||||
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
|
||||
},
|
||||
@@ -369,13 +352,12 @@
|
||||
"playersInfoPrefab": {
|
||||
"__uuid__": "b4e519f4-e698-4403-9ff2-47b8dacb077e"
|
||||
},
|
||||
"guardTowerPrefab": {
|
||||
"__uuid__": "31a63530-7811-45bc-a4ee-571faf917e35"
|
||||
},
|
||||
"forceBigEndianFloatingNumDecoding": false,
|
||||
"backgroundMapTiledIns": {
|
||||
"__id__": 4
|
||||
},
|
||||
"renderFrameIdLagTolerance": 4,
|
||||
"teleportEps1D": 0.001,
|
||||
"_id": "d12gkAmppNlIzqcRDELa91"
|
||||
},
|
||||
{
|
||||
@@ -557,7 +539,7 @@
|
||||
"array": [
|
||||
0,
|
||||
0,
|
||||
217.54856073274254,
|
||||
342.9460598986377,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
@@ -1579,6 +1561,7 @@
|
||||
"mapNode": {
|
||||
"__id__": 5
|
||||
},
|
||||
"speed": 5000,
|
||||
"_id": "76ImpM7XtPSbiLHDXdsJa+"
|
||||
},
|
||||
{
|
||||
@@ -1631,7 +1614,6 @@
|
||||
"joyStickEps": 0.1,
|
||||
"magicLeanLowerBound": 0.414,
|
||||
"magicLeanUpperBound": 2.414,
|
||||
"pollerFps": 24,
|
||||
"linearScaleFacBase": 1,
|
||||
"minScale": 1,
|
||||
"maxScale": 2,
|
||||
|
@@ -440,7 +440,7 @@
|
||||
"array": [
|
||||
0,
|
||||
0,
|
||||
209.7912853806815,
|
||||
344.75930058781137,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
@@ -2991,9 +2991,6 @@
|
||||
"loadingPrefab": {
|
||||
"__uuid__": "f2a3cece-30bf-4f62-bc20-34d44a9ddf98"
|
||||
},
|
||||
"wechatLoginTips": {
|
||||
"__id__": 68
|
||||
},
|
||||
"_id": "51YNpecnJBea8vzAxGdkv2"
|
||||
},
|
||||
{
|
||||
|
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"ver": "1.2.5",
|
||||
"uuid": "475b849b-44b3-4390-982d-bd0d9e695093",
|
||||
"asyncLoadAssets": false,
|
||||
"autoReleaseAssets": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -8,11 +8,11 @@ module.export = cc.Class({
|
||||
},
|
||||
baseSpeed: {
|
||||
type: cc.Float,
|
||||
default: 300,
|
||||
default: 50,
|
||||
},
|
||||
speed: {
|
||||
type: cc.Float,
|
||||
default: 300
|
||||
default: 50
|
||||
},
|
||||
lastMovedAt: {
|
||||
type: cc.Float,
|
||||
@@ -35,12 +35,6 @@ module.export = cc.Class({
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
start() {
|
||||
const self = this;
|
||||
self.contactedControlledPlayers = [];
|
||||
self.contactedNPCPlayers = [];
|
||||
self.coveringShelterZReducers = [];
|
||||
|
||||
self.computedNewDifferentPosLocalToParentWithinCurrentFrame = null;
|
||||
self.actionMangerSingleton = new cc.ActionManager();
|
||||
self.activeDirection = {
|
||||
dx: 0,
|
||||
dy: 0
|
||||
@@ -61,7 +55,6 @@ module.export = cc.Class({
|
||||
};
|
||||
const canvasNode = self.mapNode.parent;
|
||||
self.mapIns = self.mapNode.getComponent("Map");
|
||||
self.contactedBarriers = [];
|
||||
const joystickInputControllerScriptIns = canvasNode.getComponent("TouchEventsManager");
|
||||
self.ctrl = joystickInputControllerScriptIns;
|
||||
self.animComp = self.node.getComponent(cc.Animation);
|
||||
@@ -93,330 +86,10 @@ module.export = cc.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_addCoveringShelterZReducer(comp) {
|
||||
const self = this;
|
||||
for (let coveringShelterZReducer of self.coveringShelterZReducers) {
|
||||
if (coveringShelterZReducer._id == comp._id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.coveringShelterZReducers.push(comp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeCoveringShelterZReducer(comp) {
|
||||
const self = this;
|
||||
self.coveringShelterZReducers = self.coveringShelterZReducers.filter((coveringShelterZReducer) => {
|
||||
return coveringShelterZReducer._id != comp._id;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_addContactedBarrier(collider) {
|
||||
const self = this;
|
||||
if (!self.contactedBarriers) {
|
||||
cc.log("self.contactedBarriers is null or undefined" + self.contactedBarriers)
|
||||
}
|
||||
for (let contactedBarrier of self.contactedBarriers) {
|
||||
if (contactedBarrier._id == collider._id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.contactedBarriers.push(collider);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeContactedBarrier(collider) {
|
||||
const self = this;
|
||||
self.contactedBarriers = self.contactedBarriers.filter((contactedBarrier) => {
|
||||
return contactedBarrier._id != collider._id;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_addContactedControlledPlayers(comp) {
|
||||
const self = this;
|
||||
for (let aComp of self.contactedControlledPlayers) {
|
||||
if (aComp.uuid == comp.uuid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.contactedControlledPlayers.push(comp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeContactedControlledPlayer(comp) {
|
||||
const self = this;
|
||||
self.contactedControlledPlayers = self.contactedControlledPlayers.filter((aComp) => {
|
||||
return aComp.uuid != comp.uuid;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_addContactedNPCPlayers(comp) {
|
||||
const self = this;
|
||||
for (let aComp of self.contactedNPCPlayers) {
|
||||
if (aComp.uuid == comp.uuid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.contactedNPCPlayers.push(comp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeContactedNPCPlayer(comp) {
|
||||
const self = this;
|
||||
self.contactedNPCPlayers = self.contactedNPCPlayers.filter((aComp) => {
|
||||
return aComp.uuid != comp.uuid;
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_canMoveBy(vecToMoveBy) {
|
||||
const self = this;
|
||||
const computedNewDifferentPosLocalToParentWithinCurrentFrame = self.node.position.add(vecToMoveBy);
|
||||
self.computedNewDifferentPosLocalToParentWithinCurrentFrame = computedNewDifferentPosLocalToParentWithinCurrentFrame;
|
||||
|
||||
if (tileCollisionManager.isOutOfMapNode(self.mapNode, computedNewDifferentPosLocalToParentWithinCurrentFrame)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentSelfColliderCircle = self.node.getComponent(cc.CircleCollider);
|
||||
let nextSelfColliderCircle = null;
|
||||
if (0 < self.contactedBarriers.length) {
|
||||
/* To avoid unexpected buckling. */
|
||||
const mutatedVecToMoveBy = vecToMoveBy.mul(5); // To help it escape the engaged `contactedBarriers`.
|
||||
nextSelfColliderCircle = {
|
||||
position: self.node.position.add(mutatedVecToMoveBy).add(currentSelfColliderCircle.offset),
|
||||
radius: currentSelfColliderCircle.radius,
|
||||
};
|
||||
} else {
|
||||
nextSelfColliderCircle = {
|
||||
position: computedNewDifferentPosLocalToParentWithinCurrentFrame.add(currentSelfColliderCircle.offset),
|
||||
radius: currentSelfColliderCircle.radius,
|
||||
};
|
||||
}
|
||||
|
||||
for (let contactedBarrier of self.contactedBarriers) {
|
||||
let contactedBarrierPolygonLocalToParentWithinCurrentFrame = [];
|
||||
for (let p of contactedBarrier.points) {
|
||||
contactedBarrierPolygonLocalToParentWithinCurrentFrame.push(contactedBarrier.node.position.add(p));
|
||||
}
|
||||
if (cc.Intersection.pointInPolygon(nextSelfColliderCircle.position, contactedBarrierPolygonLocalToParentWithinCurrentFrame)) {
|
||||
// Make sure that the player is "leaving" the PolygonCollider.
|
||||
return false;
|
||||
}
|
||||
if (cc.Intersection.polygonCircle(contactedBarrierPolygonLocalToParentWithinCurrentFrame, nextSelfColliderCircle)) {
|
||||
if (null == self.firstContactedEdge) {
|
||||
return false;
|
||||
}
|
||||
if (null != self.firstContactedEdge && self.firstContactedEdge.associatedBarrier != contactedBarrier) {
|
||||
const res = self._calculateTangentialMovementAttrs(nextSelfColliderCircle, contactedBarrier);
|
||||
if (null == res.contactedEdge) {
|
||||
// Otherwise, the current movement is going to transit smoothly onto the next PolygonCollider.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
/*
|
||||
* In a subclass, use
|
||||
*
|
||||
* _canMoveBy(vecToMoveBy) {
|
||||
* BasePlayer.prototype._canMoveBy.call(this, vecToMoveBy);
|
||||
* // Customized codes.
|
||||
* }
|
||||
*
|
||||
* Reference http://www.cocos2d-x.org/docs/creator/manual/en/scripting/reference/class.html#override
|
||||
*/
|
||||
},
|
||||
|
||||
_calculateTangentialMovementAttrs(currentSelfColliderCircle, contactedBarrier) {
|
||||
/*
|
||||
* Theoretically when the `contactedBarrier` is a convex polygon and the `PlayerCollider` is a circle, there can be only 1 `contactedEdge` for each `contactedBarrier`. Except only for around the corner.
|
||||
*
|
||||
* We should avoid the possibility of players hitting the "corners of convex polygons" by map design wherever & whenever possible.
|
||||
*
|
||||
*/
|
||||
const self = this;
|
||||
const sDir = self.activeDirection;
|
||||
const currentSelfColliderCircleCentrePos = (currentSelfColliderCircle.position ? currentSelfColliderCircle.position : self.node.position.add(currentSelfColliderCircle.offset));
|
||||
const currentSelfColliderCircleRadius = currentSelfColliderCircle.radius;
|
||||
let contactedEdgeCandidateList = [];
|
||||
let skinDepthThreshold = 0.45*currentSelfColliderCircleRadius;
|
||||
for (let i = 0; i < contactedBarrier.points.length; ++i) {
|
||||
const stPoint = contactedBarrier.points[i].add(contactedBarrier.offset).add(contactedBarrier.node.position);
|
||||
const edPoint = (i == contactedBarrier.points.length - 1 ? contactedBarrier.points[0].add(contactedBarrier.offset).add(contactedBarrier.node.position) : contactedBarrier.points[1 + i].add(contactedBarrier.offset).add(contactedBarrier.node.position));
|
||||
const tmpVSt = stPoint.sub(currentSelfColliderCircleCentrePos);
|
||||
const tmpVEd = edPoint.sub(currentSelfColliderCircleCentrePos);
|
||||
const crossProdScalar = tmpVSt.cross(tmpVEd);
|
||||
if (0 < crossProdScalar) {
|
||||
// If moving parallel along `st <-> ed`, the trajectory of `currentSelfColliderCircleCentrePos` will cut inside the polygon.
|
||||
continue;
|
||||
}
|
||||
const dis = cc.Intersection.pointLineDistance(currentSelfColliderCircleCentrePos, stPoint, edPoint, true);
|
||||
if (dis > currentSelfColliderCircleRadius) continue;
|
||||
if (dis < skinDepthThreshold) continue;
|
||||
contactedEdgeCandidateList.push({
|
||||
st: stPoint,
|
||||
ed: edPoint,
|
||||
associatedBarrier: contactedBarrier,
|
||||
});
|
||||
}
|
||||
let contactedEdge = null;
|
||||
let contactedEdgeDir = null;
|
||||
let largestInnerProdAbs = Number.MIN_VALUE;
|
||||
|
||||
if (0 < contactedEdgeCandidateList.length) {
|
||||
const sDirMag = Math.sqrt(sDir.dx * sDir.dx + sDir.dy * sDir.dy);
|
||||
for (let contactedEdgeCandidate of contactedEdgeCandidateList) {
|
||||
const tmp = contactedEdgeCandidate.ed.sub(contactedEdgeCandidate.st);
|
||||
const contactedEdgeDirCandidate = {
|
||||
dx: tmp.x,
|
||||
dy: tmp.y,
|
||||
};
|
||||
const contactedEdgeDirCandidateMag = Math.sqrt(contactedEdgeDirCandidate.dx * contactedEdgeDirCandidate.dx + contactedEdgeDirCandidate.dy * contactedEdgeDirCandidate.dy);
|
||||
const innerDotProd = (sDir.dx * contactedEdgeDirCandidate.dx + sDir.dy * contactedEdgeDirCandidate.dy)/(sDirMag * contactedEdgeDirCandidateMag);
|
||||
const innerDotProdThresholdMag = 0.7;
|
||||
if ((0 > innerDotProd && innerDotProd > -innerDotProdThresholdMag) || (0 < innerDotProd && innerDotProd < innerDotProdThresholdMag)) {
|
||||
// Intentionally left blank, in this case the player is trying to escape from the `contactedEdge`.
|
||||
continue;
|
||||
} else if (innerDotProd > 0) {
|
||||
const abs = Math.abs(innerDotProd);
|
||||
if (abs > largestInnerProdAbs) {
|
||||
contactedEdgeDir = contactedEdgeDirCandidate;
|
||||
contactedEdge = contactedEdgeCandidate;
|
||||
}
|
||||
} else {
|
||||
const abs = Math.abs(innerDotProd);
|
||||
if (abs > largestInnerProdAbs) {
|
||||
contactedEdgeDir = {
|
||||
dx: -contactedEdgeDirCandidate.dx,
|
||||
dy: -contactedEdgeDirCandidate.dy,
|
||||
};
|
||||
contactedEdge = contactedEdgeCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
contactedEdgeDir: contactedEdgeDir,
|
||||
contactedEdge: contactedEdge,
|
||||
};
|
||||
},
|
||||
|
||||
_calculateVecToMoveByWithChosenDir(elapsedTime, sDir) {
|
||||
if (0 == sDir.dx && 0 == sDir.dy) {
|
||||
return cc.v2();
|
||||
}
|
||||
const self = this;
|
||||
const distanceToMove = (self.speed * elapsedTime);
|
||||
const denominator = Math.sqrt(sDir.dx * sDir.dx + sDir.dy * sDir.dy);
|
||||
const unitProjDx = (sDir.dx / denominator);
|
||||
const unitProjDy = (sDir.dy / denominator);
|
||||
return cc.v2(
|
||||
distanceToMove * unitProjDx,
|
||||
distanceToMove * unitProjDy,
|
||||
);
|
||||
},
|
||||
|
||||
_calculateVecToMoveBy(elapsedTime) {
|
||||
const self = this;
|
||||
// Note that `sDir` used in this method MUST BE a copy in RAM.
|
||||
let sDir = {
|
||||
dx: self.activeDirection.dx,
|
||||
dy: self.activeDirection.dy,
|
||||
};
|
||||
|
||||
if (0 == sDir.dx && 0 == sDir.dy) {
|
||||
return cc.v2();
|
||||
}
|
||||
|
||||
self.firstContactedEdge = null; // Reset everytime (temporary algorithm design, might change later).
|
||||
if (0 < self.contactedBarriers.length) {
|
||||
/*
|
||||
* Hardcoded to take care of only the 1st `contactedEdge` of the 1st `contactedBarrier` for now. Each `contactedBarrier` must be "counterclockwisely convex polygonal", otherwise sliding doesn't work!
|
||||
*
|
||||
*/
|
||||
const contactedBarrier = self.contactedBarriers[0];
|
||||
const currentSelfColliderCircle = self.node.getComponent(cc.CircleCollider);
|
||||
const res = self._calculateTangentialMovementAttrs(currentSelfColliderCircle, contactedBarrier);
|
||||
if (res.contactedEdge) {
|
||||
self.firstContactedEdge = res.contactedEdge;
|
||||
sDir = res.contactedEdgeDir;
|
||||
}
|
||||
}
|
||||
return self._calculateVecToMoveByWithChosenDir(elapsedTime, sDir);
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
const self = this;
|
||||
const vecToMoveBy = self._calculateVecToMoveBy(self.mapIns.rollbackEstimatedDt); // To be consistent w.r.t. rollback dynamics
|
||||
// console.log("activeDirection=", self.activeDirection, "vecToMoveBy=", vecToMoveBy, ", computedNewDifferentPosLocalToParentWithinCurrentFrame=", self.computedNewDifferentPosLocalToParentWithinCurrentFrame);
|
||||
if (self._canMoveBy(vecToMoveBy)) {
|
||||
self.node.position = self.computedNewDifferentPosLocalToParentWithinCurrentFrame;
|
||||
}
|
||||
},
|
||||
|
||||
lateUpdate(dt) {
|
||||
const self = this;
|
||||
const now = new Date().getTime();
|
||||
self.lastMovedAt = now;
|
||||
},
|
||||
|
||||
onCollisionEnter(other, self) {
|
||||
const playerScriptIns = self.node.getComponent("SelfPlayer");
|
||||
switch (other.node.name) {
|
||||
case "NPCPlayer":
|
||||
if ("NPCPlayer" != self.node.name) {
|
||||
other.node.getComponent('NPCPlayer').showProfileTrigger();
|
||||
}
|
||||
playerScriptIns._addContactedNPCPlayers(other);
|
||||
break;
|
||||
case "PolygonBoundaryBarrier":
|
||||
playerScriptIns._addContactedBarrier(other);
|
||||
break;
|
||||
case "PolygonBoundaryShelter":
|
||||
break;
|
||||
case "PolygonBoundaryShelterZReducer":
|
||||
playerScriptIns._addCoveringShelterZReducer(other);
|
||||
if (1 == playerScriptIns.coveringShelterZReducers.length) {
|
||||
setLocalZOrder(self.node, 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onCollisionStay(other, self) {
|
||||
// TBD.
|
||||
},
|
||||
|
||||
onCollisionExit(other, self) {
|
||||
const playerScriptIns = self.getComponent("SelfPlayer");
|
||||
switch (other.node.name) {
|
||||
case "NPCPlayer":
|
||||
other.node.getComponent('NPCPlayer').hideProfileTrigger();
|
||||
playerScriptIns._removeContactedNPCPlayer(other);
|
||||
break;
|
||||
case "PolygonBoundaryBarrier":
|
||||
playerScriptIns._removeContactedBarrier(other);
|
||||
break;
|
||||
case "PolygonBoundaryShelter":
|
||||
break;
|
||||
case "PolygonBoundaryShelterZReducer":
|
||||
playerScriptIns._removeCoveringShelterZReducer(other);
|
||||
if (0 == playerScriptIns.coveringShelterZReducers.length) {
|
||||
setLocalZOrder(self.node, 5);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_generateRandomDirection() {
|
||||
|
@@ -6,7 +6,10 @@ cc.Class({
|
||||
type: cc.Node,
|
||||
default: null
|
||||
},
|
||||
|
||||
speed: {
|
||||
type: cc.Float,
|
||||
default: 500
|
||||
},
|
||||
},
|
||||
|
||||
onLoad () {
|
||||
@@ -22,10 +25,13 @@ cc.Class({
|
||||
if (!self.mapScriptIns) return;
|
||||
if (!self.mapScriptIns.selfPlayerInfo) return;
|
||||
if (!self.mapScriptIns.playerRichInfoDict) return;
|
||||
const selfPlayerRichInfo = self.mapScriptIns.playerRichInfoDict[self.mapScriptIns.selfPlayerInfo.id];
|
||||
const selfPlayerRichInfo = self.mapScriptIns.playerRichInfoDict.get(self.mapScriptIns.selfPlayerInfo.id);
|
||||
if (!selfPlayerRichInfo) return;
|
||||
const selfPlayerNode = selfPlayerRichInfo.node;
|
||||
if (!selfPlayerNode) return;
|
||||
self.mainCamera.node.setPosition(selfPlayerNode.position);
|
||||
const pDiff = selfPlayerNode.position.sub(self.mainCamera.node.position);
|
||||
pDiff.normalizeSelf();
|
||||
const newCamPos = self.mainCamera.node.position.add(pDiff.mul(dt*self.speed));
|
||||
self.mainCamera.node.setPosition(newCamPos);
|
||||
}
|
||||
});
|
||||
|
@@ -26,19 +26,6 @@ cc.Class({
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
// WARNING: 不能保证在ws连接成功并且拿到boundRoomId后才运行到此处。
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
const boundRoomId = window.getBoundRoomIdFromPersistentStorage();
|
||||
const wxToShareMessage = {
|
||||
title: '夺宝大作战',
|
||||
imageUrl: 'https://mmocgame.qpic.cn/wechatgame/ibxA6JVNslX02zq6aAWCZiaWTXLYGorrVgUszo3WH1oL1CFDcFU7VKPRXPFiadxagMR/0',
|
||||
imageUrlId: 'FiLZpa5FT5GgEeEagzGBsA',
|
||||
query: 'expectedRoomId=' + boundRoomId,
|
||||
};
|
||||
console.warn("The boundRoomId for sharing: ", boundRoomId, " wxToShareMessage ", wxToShareMessage);
|
||||
wx.showShareMenu();
|
||||
wx.onShareAppMessage(() => (wxToShareMessage));
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
@@ -73,11 +60,7 @@ cc.Class({
|
||||
exitBtnOnClick(evt) {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
window.closeWSConnection();
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
cc.director.loadScene('wechatGameLogin');
|
||||
} else {
|
||||
cc.director.loadScene('login');
|
||||
}
|
||||
cc.director.loadScene('login');
|
||||
},
|
||||
|
||||
updatePlayersInfo(playerMetas) {
|
||||
@@ -107,23 +90,7 @@ cc.Class({
|
||||
if (remoteUrl == null || remoteUrl == '') {
|
||||
cc.log(`No avatar to show for :`);
|
||||
cc.log(playerMeta);
|
||||
remoteUrl = 'http://wx.qlogo.cn/mmopen/PiajxSqBRaEJUWib5D85KXWHumaxhU4E9XOn9bUpCNKF3F4ibfOj8JYHCiaoosvoXCkTmOQE1r2AKKs8ObMaz76EdA/0'
|
||||
}
|
||||
cc.loader.load({
|
||||
url: remoteUrl,
|
||||
type: 'jpg'
|
||||
}, function(err, texture) {
|
||||
if (null != err ) {
|
||||
console.error(err);
|
||||
} else {
|
||||
if (null == texture) {
|
||||
return;
|
||||
}
|
||||
const sf = new cc.SpriteFrame();
|
||||
sf.setTexture(texture);
|
||||
playerInfoNode.getChildByName('avatarMask').getChildByName('avatar').getComponent(cc.Sprite).spriteFrame = sf;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
function isEmptyString(str) {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
const i18n = require('LanguageData');
|
||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
@@ -59,55 +60,32 @@ cc.Class({
|
||||
loadingPrefab: {
|
||||
default: null,
|
||||
type: cc.Prefab
|
||||
},
|
||||
wechatLoginTips: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
|
||||
onLoad() {
|
||||
|
||||
//kobako: 腾讯统计代码
|
||||
//WARN: 打包到微信小游戏的时候会导致出错
|
||||
/*
|
||||
(function() {
|
||||
var mta = document.createElement("script");
|
||||
mta.src = "//pingjs.qq.com/h5/stats.js?v2.0.4";
|
||||
mta.setAttribute("name", "MTAH5");
|
||||
mta.setAttribute("sid", "500674632");
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(mta, s);
|
||||
})();
|
||||
*/
|
||||
|
||||
window.atFirstLocationHref = window.location.href.split('#')[0];
|
||||
const self = this;
|
||||
self.getRetCodeList();
|
||||
self.getRegexList();
|
||||
|
||||
const isUsingX5BlinkKernelOrWebkitWeChatKernel = window.isUsingX5BlinkKernelOrWebkitWeChatKernel();
|
||||
//const isUsingX5BlinkKernelOrWebkitWeChatKernel = true;
|
||||
if (!CC_DEBUG) {
|
||||
self.phoneNumberTips.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.smsLoginCaptchaButton.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.phoneNumberTips.active = true;
|
||||
self.smsLoginCaptchaButton.active = true;
|
||||
|
||||
self.captchaTips.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.phoneCountryCodeInput.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.phoneNumberInput.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.smsLoginCaptchaInput.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.captchaTips.active = true;
|
||||
self.phoneCountryCodeInput.active = true;
|
||||
self.phoneNumberInput.active = true;
|
||||
self.smsLoginCaptchaInput.active = true;
|
||||
|
||||
self.phoneLabel.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.smsLoginCaptchaLabel.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
self.phoneLabel.active = true;
|
||||
self.smsLoginCaptchaLabel.active = true;
|
||||
|
||||
self.loginButton.active = !isUsingX5BlinkKernelOrWebkitWeChatKernel;
|
||||
}
|
||||
self.checkPhoneNumber = self.checkPhoneNumber.bind(self);
|
||||
self.checkIntAuthTokenExpire = self.checkIntAuthTokenExpire.bind(self);
|
||||
self.checkCaptcha = self.checkCaptcha.bind(self);
|
||||
self.onSMSCaptchaGetButtonClicked = self.onSMSCaptchaGetButtonClicked.bind(self);
|
||||
self.loginButton.active = true;
|
||||
self.onLoginButtonClicked = self.onLoginButtonClicked.bind(self);
|
||||
self.onSMSCaptchaGetButtonClicked = self.onSMSCaptchaGetButtonClicked.bind(self);
|
||||
self.smsLoginCaptchaButton.on('click', self.onSMSCaptchaGetButtonClicked);
|
||||
|
||||
self.loadingNode = cc.instantiate(this.loadingPrefab);
|
||||
@@ -124,35 +102,21 @@ cc.Class({
|
||||
cc.error(err.message || err);
|
||||
return;
|
||||
}
|
||||
if (false == (cc.sys.platform == cc.sys.WECHAT_GAME)) {
|
||||
// Otherwise, `window.RoomDownsyncFrame` is already assigned.
|
||||
let protoRoot = new protobuf.Root;
|
||||
window.protobuf.parse(textAsset.text, protoRoot);
|
||||
window.RoomDownsyncFrame = protoRoot.lookupType("treasurehunterx.RoomDownsyncFrame");
|
||||
window.BattleColliderInfo = protoRoot.lookupType("treasurehunterx.BattleColliderInfo");
|
||||
window.WsReq = protoRoot.lookupType("treasurehunterx.WsReq");
|
||||
window.WsResp = protoRoot.lookupType("treasurehunterx.WsResp");
|
||||
}
|
||||
// Otherwise, `window.RoomDownsyncFrame` is already assigned.
|
||||
let protoRoot = new protobuf.Root;
|
||||
window.protobuf.parse(textAsset.text, protoRoot);
|
||||
window.RoomDownsyncFrame = protoRoot.lookupType("treasurehunterx.RoomDownsyncFrame");
|
||||
window.BattleColliderInfo = protoRoot.lookupType("treasurehunterx.BattleColliderInfo");
|
||||
window.WsReq = protoRoot.lookupType("treasurehunterx.WsReq");
|
||||
window.WsResp = protoRoot.lookupType("treasurehunterx.WsResp");
|
||||
self.checkIntAuthTokenExpire().then(
|
||||
() => {
|
||||
const intAuthToken = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')).intAuthToken;
|
||||
(intAuthToken) => {
|
||||
console.log("Successfully found `intAuthToken` in local cache");
|
||||
self.useTokenLogin(intAuthToken);
|
||||
},
|
||||
() => {
|
||||
console.warn("Failed to find `intAuthToken` in local cache");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
if ( (CC_DEBUG || isUsingX5BlinkKernelOrWebkitWeChatKernel) ) {
|
||||
if (null != qDict && qDict["code"]) {
|
||||
const code = qDict["code"];
|
||||
console.log("Got the wx authcode: ", code, "while at full url: " + window.location.href);
|
||||
self.useWXCodeLogin(code);
|
||||
} else {
|
||||
if (isUsingX5BlinkKernelOrWebkitWeChatKernel) {
|
||||
self.getWechatCode(null);
|
||||
} else {
|
||||
// Deliberately left blank.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -243,11 +207,28 @@ cc.Class({
|
||||
checkIntAuthTokenExpire() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!cc.sys.localStorage.getItem('selfPlayer')) {
|
||||
console.warn("Couldn't find selfPlayer key in local cache");
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
(selfPlayer.intAuthToken && new Date().getTime() < selfPlayer.expiresAt) ? resolve() : reject();
|
||||
if (null == selfPlayer) {
|
||||
console.warn("Couldn't find selfPlayer object in local cache");
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (null == selfPlayer.intAuthToken) {
|
||||
console.warn("Couldn't find selfPlayer object with key `intAuthToken` in local cache");
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
if (new Date().getTime() > selfPlayer.expiresAt) {
|
||||
console.warn("Couldn't find unexpired selfPlayer `intAuthToken` in local cache");
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
resolve(selfPlayer.intAuthToken);
|
||||
})
|
||||
},
|
||||
|
||||
@@ -300,13 +281,15 @@ cc.Class({
|
||||
intAuthToken: _intAuthToken
|
||||
},
|
||||
success: function(resp) {
|
||||
console.log("Login attempt `useTokenLogin` succeeded.");
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `useTokenLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
console.warn("Login attempt `useTokenLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
},
|
||||
timeout: function() {
|
||||
console.warn("Login attempt `useTokenLogin` timed out, about to enable interactive controls.");
|
||||
self.enableInteractiveControls(true);
|
||||
},
|
||||
});
|
||||
@@ -355,46 +338,10 @@ cc.Class({
|
||||
});
|
||||
},
|
||||
|
||||
onWechatLoggedIn(res) {
|
||||
const self = this;
|
||||
if (res.ret === self.retCodeDict.OK) {
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
displayName: res.displayName,
|
||||
avatar: res.avatar,
|
||||
}
|
||||
cc.sys.localStorage.setItem('selfPlayer', JSON.stringify(selfPlayer));
|
||||
|
||||
const qDict = window.getQueryParamDict();
|
||||
const expectedRoomId = qDict["expectedRoomId"];
|
||||
if (null != expectedRoomId) {
|
||||
console.log("onWechatLoggedIn using expectedRoomId == " + expectedRoomId);
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
}
|
||||
// To remove "code=XXX" in "query string".
|
||||
window.history.replaceState(qDict, null, window.location.pathname);
|
||||
self.useTokenLogin(res.intAuthToken);
|
||||
} else {
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.wechatLoginTips.string = constants.ALERT.TIP_LABEL.WECHAT_LOGIN_FAILS + ", errorCode = " + res.ret;
|
||||
// To remove "code=XXX" in "query string".
|
||||
window.history.replaceState({}, null, window.location.pathname);
|
||||
}
|
||||
},
|
||||
|
||||
onLoggedIn(res) {
|
||||
const self = this;
|
||||
cc.log(`OnLoggedIn ${JSON.stringify(res)}.`)
|
||||
console.log("OnLoggedIn ", JSON.stringify(res))
|
||||
if (res.ret === self.retCodeDict.OK) {
|
||||
if(window.isUsingX5BlinkKernelOrWebkitWeChatKernel()) {
|
||||
window.initWxSdk = self.initWxSdk.bind(self);
|
||||
window.initWxSdk();
|
||||
}
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
@@ -418,6 +365,7 @@ cc.Class({
|
||||
);
|
||||
cc.director.loadScene('default_map');
|
||||
} else {
|
||||
console.log("OnLoggedIn failed, about to remove `selfPlayer` in local cache.")
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.enableInteractiveControls(true);
|
||||
@@ -451,105 +399,4 @@ cc.Class({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
useWXCodeLogin(_code) {
|
||||
const self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
code: _code
|
||||
},
|
||||
success: function(res) {
|
||||
self.onWechatLoggedIn(res);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `useWXCodeLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.wechatLoginTips.string = constants.ALERT.TIP_LABEL.WECHAT_LOGIN_FAILS + ", errorMsg =" + errMsg;
|
||||
window.history.replaceState({}, null, window.location.pathname);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getWechatCode(evt) {
|
||||
let self = this;
|
||||
self.wechatLoginTips.string = "";
|
||||
const wechatServerEndpoint = wechatAddress.PROTOCOL + "://" + wechatAddress.HOST + ((null != wechatAddress.PORT && "" != wechatAddress.PORT.trim()) ? (":" + wechatAddress.PORT) : "");
|
||||
const url = wechatServerEndpoint + constants.WECHAT.AUTHORIZE_PATH + "?" + wechatAddress.APPID_LITERAL + "&" + constants.WECHAT.REDIRECT_RUI_KEY + NetworkUtils.encode(window.location.href) + "&" + constants.WECHAT.RESPONSE_TYPE + "&" + constants.WECHAT.SCOPE + constants.WECHAT.FIN;
|
||||
console.log("To visit wechat auth addr: " + url);
|
||||
window.location.href = url;
|
||||
},
|
||||
|
||||
initWxSdk() {
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
const origUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
/*
|
||||
* The `shareLink` must
|
||||
* - have its 2nd-order-domain registered as trusted 2nd-order under the targetd `res.jsConfig.app_id`, and
|
||||
* - extracted from current window.location.href.
|
||||
*/
|
||||
const shareLink = origUrl;
|
||||
const updateAppMsgShareDataObj = {
|
||||
type: 'link', // 分享类型,music、video或link,不填默认为link
|
||||
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
|
||||
title: document.title, // 分享标题
|
||||
desc: 'Let\'s play together!', // 分享描述
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {
|
||||
// 设置成功
|
||||
}
|
||||
};
|
||||
const menuShareTimelineObj = {
|
||||
title: document.title, // 分享标题
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {}
|
||||
};
|
||||
|
||||
const wxConfigUrl = (window.isUsingWebkitWechatKernel() ? window.atFirstLocationHref : window.location.href);
|
||||
//接入微信登录接口
|
||||
NetworkUtils.ajax({
|
||||
"url": backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.JSCONFIG,
|
||||
type: "POST",
|
||||
data: {
|
||||
"url": wxConfigUrl,
|
||||
"intAuthToken": selfPlayer.intAuthToken,
|
||||
},
|
||||
success: function(res) {
|
||||
if (constants.RET_CODE.OK != res.ret) {
|
||||
console.log("cannot get the wsConfig. retCode == " + res.ret);
|
||||
return;
|
||||
}
|
||||
const jsConfig = res.jsConfig;
|
||||
console.log(updateAppMsgShareDataObj);
|
||||
const configData = {
|
||||
debug: CC_DEBUG, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
||||
appId: jsConfig.app_id, // 必填,公众号的唯一标识
|
||||
timestamp: jsConfig.timestamp.toString(), // 必填,生成签名的时间戳
|
||||
nonceStr: jsConfig.nonce_str, // 必填,生成签名的随机串
|
||||
jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline'],
|
||||
signature: jsConfig.signature, // 必填,签名
|
||||
};
|
||||
console.log("config url: " + wxConfigUrl);
|
||||
console.log("wx.config: ");
|
||||
console.log(configData);
|
||||
wx.config(configData);
|
||||
console.log("Current window.location.href: " + window.location.href);
|
||||
wx.ready(function() {
|
||||
console.log("Here is wx.ready.")
|
||||
wx.onMenuShareAppMessage(updateAppMsgShareDataObj);
|
||||
wx.onMenuShareTimeline(menuShareTimelineObj);
|
||||
});
|
||||
wx.error(function(res) {
|
||||
console.error("wx config fails and error is " + JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("cannot get the wsConfig. errMsg == " + errMsg);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
100
frontend/assets/scripts/RingBuffer.js
Normal file
@@ -0,0 +1,100 @@
|
||||
window.RING_BUFF_CONSECUTIVE_SET = 0;
|
||||
window.RING_BUFF_NON_CONSECUTIVE_SET = 1;
|
||||
window.RING_BUFF_FAILED_TO_SET = 2;
|
||||
|
||||
var RingBuffer = function(capacity) {
|
||||
this.ed = 0; // write index, open index
|
||||
this.st = 0; // read index, closed index
|
||||
this.edFrameId = 0;
|
||||
this.stFrameId = 0;
|
||||
this.n = capacity;
|
||||
this.cnt = 0; // the count of valid elements in the buffer, used mainly to distinguish what "st == ed" means for "Pop" and "Get" methods
|
||||
this.eles = new Array(capacity).fill(null);
|
||||
};
|
||||
|
||||
RingBuffer.prototype.put = function(item) {
|
||||
this.eles[this.ed] = item
|
||||
this.edFrameId++;
|
||||
this.cnt++;
|
||||
this.ed++;
|
||||
if (this.ed >= this.n) {
|
||||
this.ed -= this.n; // Deliberately not using "%" operator for performance concern
|
||||
}
|
||||
};
|
||||
|
||||
RingBuffer.prototype.pop = function() {
|
||||
if (0 == this.cnt) {
|
||||
return null;
|
||||
}
|
||||
const item = this.eles[this.st];
|
||||
this.stFrameId++;
|
||||
this.cnt--;
|
||||
this.st++;
|
||||
if (this.st >= this.n) {
|
||||
this.st -= this.n;
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
RingBuffer.prototype.getArrIdxByOffset = function(offsetFromSt) {
|
||||
if (0 > offsetFromSt || 0 == this.cnt) {
|
||||
return null;
|
||||
}
|
||||
let arrIdx = this.st + offsetFromSt;
|
||||
if (this.st < this.ed) {
|
||||
// case#1: 0...st...ed...n-1
|
||||
if (this.st <= arrIdx && arrIdx < this.ed) {
|
||||
return arrIdx;
|
||||
}
|
||||
} else {
|
||||
// if this.st >= this.sd
|
||||
// case#2: 0...ed...st...n-1
|
||||
if (arrIdx >= this.n) {
|
||||
arrIdx -= this.n
|
||||
}
|
||||
if (arrIdx >= this.st || arrIdx < this.ed) {
|
||||
return arrIdx;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
RingBuffer.prototype.getByFrameId = function(frameId) {
|
||||
const arrIdx = this.getArrIdxByOffset(frameId - this.stFrameId);
|
||||
return (null == arrIdx ? null : this.eles[arrIdx]);
|
||||
};
|
||||
|
||||
// [WARNING] During a battle, frontend could receive non-consecutive frames (either renderFrame or inputFrame) due to resync, the buffer should handle these frames properly.
|
||||
RingBuffer.prototype.setByFrameId = function(item, frameId) {
|
||||
if (frameId < this.stFrameId) {
|
||||
console.error("Invalid putByFrameId#1: stFrameId=", this.stFrameId, ", edFrameId=", this.edFrameId, ", incoming item=", item);
|
||||
return window.RING_BUFF_FAILED_TO_SET;
|
||||
}
|
||||
const arrIdx = this.getArrIdxByOffset(frameId - this.stFrameId);
|
||||
if (null != arrIdx) {
|
||||
this.eles[arrIdx] = item;
|
||||
return window.RING_BUFF_CONSECUTIVE_SET;
|
||||
}
|
||||
|
||||
// When "null == arrIdx", should it still be deemed consecutive if "frameId == edFrameId" prior to the reset?
|
||||
let ret = window.RING_BUFF_CONSECUTIVE_SET;
|
||||
if (this.edFrameId < frameId) {
|
||||
this.st = this.ed = 0;
|
||||
this.stFrameId = this.edFrameId = frameId;
|
||||
this.cnt = 0;
|
||||
ret = window.RING_BUFF_NON_CONSECUTIVE_SET;
|
||||
}
|
||||
|
||||
this.eles[this.ed] = item
|
||||
this.edFrameId++;
|
||||
this.cnt++;
|
||||
this.ed++;
|
||||
if (this.ed >= this.n) {
|
||||
this.ed -= this.n; // Deliberately not using "%" operator for performance concern
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
module.exports = RingBuffer;
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "8264fb72-e348-45e4-9ab3-5bffb9a561ee",
|
||||
"uuid": "9ec706f0-811c-403b-93a7-b34a7e5f8068",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
@@ -334,10 +334,6 @@ window.battleEntityTypeNameToGlobalGid = {};
|
||||
TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNode) {
|
||||
let toRet = {
|
||||
barriers: [],
|
||||
shelters: [],
|
||||
shelterChainTails: [],
|
||||
shelterChainHeads: [],
|
||||
sheltersZReducer: [],
|
||||
frameAnimations: [],
|
||||
grandBoundaries: [],
|
||||
};
|
||||
@@ -393,8 +389,6 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo
|
||||
let childrenOfCurrentTile = null;
|
||||
if (cc.sys.isNative) {
|
||||
childrenOfCurrentTile = currentTile.getElementsByTagName("objectgroup");
|
||||
} else if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
childrenOfCurrentTile = currentTile.childNodes;
|
||||
} else {
|
||||
childrenOfCurrentTile = currentTile.children;
|
||||
}
|
||||
@@ -404,8 +398,6 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo
|
||||
var currentObjectGroupUnderTile = mapInfo._parseObjectGroup(ch);
|
||||
gidBoundariesMap[parentGid] = {
|
||||
barriers: [],
|
||||
shelters: [],
|
||||
sheltersZReducer: [],
|
||||
};
|
||||
for (let oidx = 0; oidx < currentObjectGroupUnderTile._objects.length; ++oidx) {
|
||||
const oo = currentObjectGroupUnderTile._objects[oidx];
|
||||
@@ -429,22 +421,6 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo
|
||||
brToPushTmp.boundaryType = boundaryType;
|
||||
gidBoundariesMap[parentGid].barriers.push(brToPushTmp);
|
||||
break;
|
||||
case "shelter":
|
||||
let shToPushTmp = [];
|
||||
for (let shidx = 0; shidx < polylinePoints.length; ++shidx) {
|
||||
shToPushTmp.push(cc.v2(oo.x, oo.y).add(polylinePoints[shidx]));
|
||||
}
|
||||
shToPushTmp.boundaryType = boundaryType;
|
||||
gidBoundariesMap[parentGid].shelters.push(shToPushTmp);
|
||||
break;
|
||||
case "shelter_z_reducer":
|
||||
let shzrToPushTmp = [];
|
||||
for (let shzridx = 0; shzridx < polylinePoints.length; ++shzridx) {
|
||||
shzrToPushTmp.push(cc.v2(oo.x, oo.y).add(polylinePoints[shzridx]));
|
||||
}
|
||||
shzrToPushTmp.boundaryType = boundaryType;
|
||||
gidBoundariesMap[parentGid].sheltersZReducer.push(shzrToPushTmp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -510,22 +486,6 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo
|
||||
toPushBarriers.boundaryType = boundaryType;
|
||||
toRet.barriers.push(toPushBarriers);
|
||||
break;
|
||||
case "shelter":
|
||||
let toPushShelters = [];
|
||||
for (let kk = 0; kk < polylinePoints.length; ++kk) {
|
||||
toPushShelters.push(this.continuousObjLayerOffsetToContinuousMapNodePos(withTiledMapNode, object.offset.add(polylinePoints[kk])));
|
||||
}
|
||||
toPushShelters.boundaryType = boundaryType;
|
||||
toRet.shelters.push(toPushShelters);
|
||||
break;
|
||||
case "shelter_z_reducer":
|
||||
let toPushSheltersZReducer = [];
|
||||
for (let kkk = 0; kkk < polylinePoints.length; ++kkk) {
|
||||
toPushSheltersZReducer.push(this.continuousObjLayerOffsetToContinuousMapNodePos(withTiledMapNode, object.offset.add(polylinePoints[kkk])));
|
||||
}
|
||||
toPushSheltersZReducer.boundaryType = boundaryType;
|
||||
toRet.sheltersZReducer.push(toPushSheltersZReducer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -536,7 +496,7 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo
|
||||
|
||||
let layerDOMTrees = [];
|
||||
const mapDomTree = mapInfo._parser._parseXML(tiledMapIns.tmxAsset.tmxXmlStr).documentElement;
|
||||
const mapDOMAllChildren = (cc.sys.platform == cc.sys.WECHAT_GAME ? mapDomTree.childNodes : mapDomTree.children);
|
||||
const mapDOMAllChildren = (mapDomTree.children);
|
||||
for (let mdtIdx = 0; mdtIdx < mapDOMAllChildren.length; ++mdtIdx) {
|
||||
const tmpCh = mapDOMAllChildren[mdtIdx];
|
||||
if (mapInfo._shouldIgnoreNode(tmpCh)) {
|
||||
@@ -585,23 +545,6 @@ TileCollisionManager.prototype.extractBoundaryObjects = function (withTiledMapNo
|
||||
}
|
||||
toRet.barriers.push(brToPushTmp);
|
||||
}
|
||||
for (let shidx = 0; shidx < gidBoundaries.shelters.length; ++shzridx) {
|
||||
const theShelter = gidBoundaries.shelters[shidx]; // An array of cc.v2 points.
|
||||
let shToPushTmp = [];
|
||||
for (let tshidx = 0; tshidx < theShelter.length; ++tshidx) {
|
||||
shToPushTmp.push(topLeftOfWholeTsxTileInMapNode.add(cc.v2(theShelter[tshidx].x, -theShelter[tshidx].y)));
|
||||
}
|
||||
toRet.shelters.push(shToPushTmp);
|
||||
}
|
||||
for (let shzridx = 0; shzridx < gidBoundaries.sheltersZReducer.length; ++shzridx) {
|
||||
const theShelter = gidBoundaries.sheltersZReducer[shzridx]; // An array of cc.v2 points.
|
||||
let shzrToPushTmp = [];
|
||||
for (let tshzridx = 0; tshzridx < theShelter.length; ++tshzridx) {
|
||||
shzrToPushTmp.push(topLeftOfWholeTsxTileInMapNode.add(cc.v2(theShelter[tshzridx].x, -theShelter[tshzridx].y)));
|
||||
}
|
||||
toRet.sheltersZReducer.push(shzrToPushTmp);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
@@ -637,6 +580,7 @@ TileCollisionManager.prototype.isOutOfMapNode = function (tiledMapNode, continuo
|
||||
};
|
||||
|
||||
TileCollisionManager.prototype.initMapNodeByTiledBoundaries = function(mapScriptIns, mapNode, extractedBoundaryObjs) {
|
||||
// TODO: TO DEPRECATE!
|
||||
const tiledMapIns = mapNode.getComponent(cc.TiledMap);
|
||||
if (extractedBoundaryObjs.grandBoundaries) {
|
||||
window.grandBoundary = [];
|
||||
@@ -683,47 +627,6 @@ TileCollisionManager.prototype.initMapNodeByTiledBoundaries = function(mapScript
|
||||
frameAnimInType.push(animNode);
|
||||
}
|
||||
|
||||
for (let boundaryObj of extractedBoundaryObjs.shelterChainTails) {
|
||||
const newShelter = cc.instantiate(mapScriptIns.polygonBoundaryShelterPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newShelter.setPosition(newBoundaryOffsetInMapNode);
|
||||
newShelter.setAnchorPoint(cc.v2(0, 0));
|
||||
const newShelterColliderIns = newShelter.getComponent(cc.PolygonCollider);
|
||||
newShelterColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newShelterColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
newShelter.pTiledLayer = boundaryObj.pTiledLayer;
|
||||
newShelter.tileDiscretePos = boundaryObj.tileDiscretePos;
|
||||
if (null != boundaryObj.imageObject) {
|
||||
newShelter.imageObject = boundaryObj.imageObject;
|
||||
newShelter.tailOrHead = "tail";
|
||||
window.addToGlobalShelterChainVerticeMap(newShelter.imageObject.imageObjectNode); // Deliberately NOT adding at the "traversal of shelterChainHeads".
|
||||
}
|
||||
newShelter.boundaryObj = boundaryObj;
|
||||
mapScriptIns.node.addChild(newShelter);
|
||||
}
|
||||
|
||||
for (let boundaryObj of extractedBoundaryObjs.shelterChainHeads) {
|
||||
const newShelter = cc.instantiate(mapScriptIns.polygonBoundaryShelterPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newShelter.setPosition(newBoundaryOffsetInMapNode);
|
||||
newShelter.setAnchorPoint(cc.v2(0, 0));
|
||||
const newShelterColliderIns = newShelter.getComponent(cc.PolygonCollider);
|
||||
newShelterColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newShelterColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
newShelter.pTiledLayer = boundaryObj.pTiledLayer;
|
||||
newShelter.tileDiscretePos = boundaryObj.tileDiscretePos;
|
||||
if (null != boundaryObj.imageObject) {
|
||||
newShelter.imageObject = boundaryObj.imageObject;
|
||||
newShelter.tailOrHead = "head";
|
||||
}
|
||||
newShelter.boundaryObj = boundaryObj;
|
||||
mapScriptIns.node.addChild(newShelter);
|
||||
}
|
||||
|
||||
mapScriptIns.barrierColliders = [];
|
||||
for (let boundaryObj of extractedBoundaryObjs.barriers) {
|
||||
const newBarrier = cc.instantiate(mapScriptIns.polygonBoundaryBarrierPrefab);
|
||||
@@ -739,19 +642,6 @@ TileCollisionManager.prototype.initMapNodeByTiledBoundaries = function(mapScript
|
||||
mapScriptIns.node.addChild(newBarrier);
|
||||
}
|
||||
|
||||
for (let boundaryObj of extractedBoundaryObjs.sheltersZReducer) {
|
||||
const newShelter = cc.instantiate(mapScriptIns.polygonBoundaryShelterZReducerPrefab);
|
||||
const newBoundaryOffsetInMapNode = cc.v2(boundaryObj[0].x, boundaryObj[0].y);
|
||||
newShelter.setPosition(newBoundaryOffsetInMapNode);
|
||||
newShelter.setAnchorPoint(cc.v2(0, 0));
|
||||
const newShelterColliderIns = newShelter.getComponent(cc.PolygonCollider);
|
||||
newShelterColliderIns.points = [];
|
||||
for (let p of boundaryObj) {
|
||||
newShelterColliderIns.points.push(p.sub(newBoundaryOffsetInMapNode));
|
||||
}
|
||||
mapScriptIns.node.addChild(newShelter);
|
||||
}
|
||||
|
||||
const allLayers = tiledMapIns.getLayers();
|
||||
for (let layer of allLayers) {
|
||||
const layerType = layer.getProperty("type");
|
||||
@@ -759,10 +649,6 @@ TileCollisionManager.prototype.initMapNodeByTiledBoundaries = function(mapScript
|
||||
case "barrier_and_shelter":
|
||||
setLocalZOrder(layer.node, 3);
|
||||
break;
|
||||
case "shelter_preview":
|
||||
layer.node.opacity = 100;
|
||||
setLocalZOrder(layer.node, 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@@ -1,17 +1,18 @@
|
||||
window.DIRECTION_DECODER = [
|
||||
[0, 0],
|
||||
[0, +1],
|
||||
[0, -1],
|
||||
[+2, 0],
|
||||
[-2, 0],
|
||||
[+2, +1],
|
||||
[-2, -1],
|
||||
[+2, -1],
|
||||
[-2, +1],
|
||||
[+2, 0],
|
||||
[-2, 0],
|
||||
[0, +1],
|
||||
[0, -1],
|
||||
// The 3rd value matches low-precision constants in backend.
|
||||
[0, 0, 0.0],
|
||||
[0, +1, 1.0],
|
||||
[0, -1, 1.0],
|
||||
[+2, 0, 0.5],
|
||||
[-2, 0, 0.5],
|
||||
[+2, +1, 0.4472],
|
||||
[-2, -1, 0.4472],
|
||||
[+2, -1, 0.4472],
|
||||
[-2, +1, 0.4472],
|
||||
[+2, 0, 0.5],
|
||||
[-2, 0, 0.5],
|
||||
[0, +1, 1.0],
|
||||
[0, -1, 1.0],
|
||||
];
|
||||
|
||||
cc.Class({
|
||||
@@ -114,43 +115,6 @@ cc.Class({
|
||||
this.initialized = true;
|
||||
},
|
||||
|
||||
justifyMapNodePosAndScale(linearSpeedBase, zoomingSpeedBase) {
|
||||
const self = this;
|
||||
if (false == self.mapScriptIns._inputControlEnabled) return;
|
||||
if (null != self._cachedMapNodePosTarget) {
|
||||
while (self.maxMovingBufferLength < self._cachedMapNodePosTarget.length) {
|
||||
self._cachedMapNodePosTarget.shift();
|
||||
}
|
||||
if (0 < self._cachedMapNodePosTarget.length && 0 == self.mapNode.getNumberOfRunningActions()) {
|
||||
const nextMapNodePosTarget = self._cachedMapNodePosTarget.shift();
|
||||
const linearSpeed = linearSpeedBase;
|
||||
const finalDiffVec = nextMapNodePosTarget.pos.sub(self.mapNode.position);
|
||||
const finalDiffVecMag = finalDiffVec.mag();
|
||||
if (self.linearMovingEps > finalDiffVecMag) {
|
||||
// Jittering.
|
||||
// cc.log("Map node moving by finalDiffVecMag == %s is just jittering.", finalDiffVecMag);
|
||||
return;
|
||||
}
|
||||
const durationSeconds = finalDiffVecMag / linearSpeed;
|
||||
cc.log("Map node moving to %o in %s/%s == %s seconds.", nextMapNodePosTarget.pos, finalDiffVecMag, linearSpeed, durationSeconds);
|
||||
const bufferedTargetPos = cc.v2(nextMapNodePosTarget.pos.x, nextMapNodePosTarget.pos.y);
|
||||
self.mapNode.runAction(cc.sequence(
|
||||
cc.moveTo(durationSeconds, bufferedTargetPos),
|
||||
cc.callFunc(() => {
|
||||
if (self._isMapOverMoved(self.mapNode.position)) {
|
||||
self.mapNode.setPosition(bufferedTargetPos);
|
||||
}
|
||||
}, self)
|
||||
));
|
||||
}
|
||||
}
|
||||
if (null != self._cachedZoomRawTarget && false == self._cachedZoomRawTarget.processed) {
|
||||
cc.log(`Processing self._cachedZoomRawTarget == ${self._cachedZoomRawTarget}`);
|
||||
self._cachedZoomRawTarget.processed = true;
|
||||
self.mapNode.setScale(self._cachedZoomRawTarget.scale);
|
||||
}
|
||||
},
|
||||
|
||||
_initTouchEvent() {
|
||||
const self = this;
|
||||
const translationListenerNode = (self.translationListenerNode ? self.translationListenerNode : self.mapNode);
|
||||
@@ -377,7 +341,8 @@ cc.Class({
|
||||
}
|
||||
return {
|
||||
dx: mapped[0],
|
||||
dy: mapped[1]
|
||||
dy: mapped[1],
|
||||
speedFactor: mapped[2],
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -1,628 +0,0 @@
|
||||
const i18n = require('LanguageData');
|
||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||
|
||||
const WECHAT_ON_HIDE_TARGET_ACTION = {
|
||||
SHARE_CHAT_MESSAGE: 8,
|
||||
CLOSE: 3,
|
||||
};
|
||||
|
||||
const pbStructRoot = require('./modules/room_downsync_frame_proto_bundle.forcemsg.js');
|
||||
window.RoomDownsyncFrame = pbStructRoot.treasurehunterx.RoomDownsyncFrame;
|
||||
window.BattleColliderInfo = pbStructRoot.treasurehunterx.BattleColliderInfo;
|
||||
|
||||
cc.Class({
|
||||
extends: cc.Component,
|
||||
|
||||
properties: {
|
||||
cavasNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
backgroundNode: {
|
||||
default: null,
|
||||
type: cc.Node
|
||||
},
|
||||
loadingPrefab: {
|
||||
default: null,
|
||||
type: cc.Prefab
|
||||
},
|
||||
tipsLabel: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
|
||||
downloadProgress: {
|
||||
default: null,
|
||||
type: cc.ProgressBar,
|
||||
},
|
||||
writtenBytes: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
expectedToWriteBytes: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
|
||||
handlerProgress: {
|
||||
default: null,
|
||||
type: cc.ProgressBar,
|
||||
},
|
||||
handledUrlsCount: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
toHandledUrlsCount: {
|
||||
default: null,
|
||||
type: cc.Label,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
// LIFE-CYCLE CALLBACKS:
|
||||
onLoad() {
|
||||
wx.onShow((res) => {
|
||||
console.log("+++++ wx onShow(), onShow.res ", res);
|
||||
window.expectedRoomId = res.query.expectedRoomId;
|
||||
});
|
||||
wx.onHide((res) => {
|
||||
// Reference https://developers.weixin.qq.com/minigame/dev/api/wx.exitMiniProgram.html.
|
||||
console.log("+++++ wx onHide(), onHide.res: ", res);
|
||||
if (
|
||||
WECHAT_ON_HIDE_TARGET_ACTION == res.targetAction
|
||||
||
|
||||
"back" == res.mode // After "WeChat v7.0.4 on iOS"
|
||||
||
|
||||
"close" == res.mode
|
||||
) {
|
||||
window.clearLocalStorageAndBackToLoginScene();
|
||||
} else {
|
||||
// Deliberately left blank.
|
||||
}
|
||||
});
|
||||
|
||||
const self = this;
|
||||
self.getRetCodeList();
|
||||
self.getRegexList();
|
||||
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_1"));
|
||||
self.checkIntAuthTokenExpire().then(
|
||||
() => {
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_2"));
|
||||
const intAuthToken = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')).intAuthToken;
|
||||
self.useTokenLogin(intAuthToken);
|
||||
},
|
||||
() => {
|
||||
// 调用wx.login然后请求登录。
|
||||
wx.authorize({
|
||||
scope: "scope.userInfo",
|
||||
success() {
|
||||
self.showTips(i18n.t("login.tips.WECHAT_AUTHORIZED_AND_INT_AUTH_TOKEN_LOGGING_IN"));
|
||||
wx.login({
|
||||
success(res) {
|
||||
console.log("wx login success, res: ", res);
|
||||
const code = res.code;
|
||||
|
||||
wx.getUserInfo({
|
||||
success(res) {
|
||||
const userInfo = res.userInfo;
|
||||
console.log("Get user info ok: ", userInfo);
|
||||
self.useWxCodeMiniGameLogin(code, userInfo);
|
||||
},
|
||||
fail(err) {
|
||||
console.error(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
})
|
||||
},
|
||||
fail(err) {
|
||||
if (err) {
|
||||
console.error(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
fail(err) {
|
||||
console.error(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
createAuthorizeThenLoginButton(tips) {
|
||||
const self = this;
|
||||
|
||||
let sysInfo = wx.getSystemInfoSync();
|
||||
//获取微信界面大小
|
||||
let width = sysInfo.screenWidth;
|
||||
let height = sysInfo.screenHeight;
|
||||
|
||||
let button = wx.createUserInfoButton({
|
||||
type: 'text',
|
||||
text: '',
|
||||
style: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: width,
|
||||
height: height,
|
||||
backgroundColor: '#00000000', //最后两位为透明度
|
||||
color: '#ffffff',
|
||||
fontSize: 20,
|
||||
textAlign: "center",
|
||||
lineHeight: height,
|
||||
},
|
||||
});
|
||||
button.onTap((res) => {
|
||||
console.log(res);
|
||||
if (null != res.userInfo) {
|
||||
const userInfo = res.userInfo;
|
||||
self.showTips(i18n.t("login.tips.WECHAT_AUTHORIZED_AND_INT_AUTH_TOKEN_LOGGING_IN"));
|
||||
|
||||
wx.login({
|
||||
success(res) {
|
||||
console.log('wx.login success, res:', res);
|
||||
const code = res.code;
|
||||
self.useWxCodeMiniGameLogin(code, userInfo);
|
||||
button.destroy();
|
||||
},
|
||||
fail(err) {
|
||||
console.err(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"), err);
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
self.showTips(i18n.t("login.tips.PLEASE_AUTHORIZE_WECHAT_LOGIN_FIRST"));
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
onDestroy() {
|
||||
console.log("+++++++ WechatGameLogin onDestroy()");
|
||||
},
|
||||
|
||||
showTips(text) {
|
||||
if (this.tipsLabel != null) {
|
||||
this.tipsLabel.string = text;
|
||||
} else {
|
||||
console.log('Login scene showTips failed')
|
||||
}
|
||||
},
|
||||
|
||||
getRetCodeList() {
|
||||
const self = this;
|
||||
self.retCodeDict = constants.RET_CODE;
|
||||
},
|
||||
|
||||
getRegexList() {
|
||||
const self = this;
|
||||
self.regexList = {
|
||||
EMAIL: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||
PHONE: /^\+?[0-9]{8,14}$/,
|
||||
STREET_META: /^.{5,100}$/,
|
||||
LNG_LAT_TEXT: /^[0-9]+(\.[0-9]{4,6})$/,
|
||||
SEO_KEYWORD: /^.{2,50}$/,
|
||||
PASSWORD: /^.{6,50}$/,
|
||||
SMS_CAPTCHA_CODE: /^[0-9]{4}$/,
|
||||
ADMIN_HANDLE: /^.{4,50}$/,
|
||||
};
|
||||
},
|
||||
|
||||
onSMSCaptchaGetButtonClicked(evt) {
|
||||
var timerEnable = true;
|
||||
const self = this;
|
||||
if (!self.checkPhoneNumber('getCaptcha')) {
|
||||
return;
|
||||
}
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER +
|
||||
constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.SMS_CAPTCHA + constants.ROUTE_PATH.GET,
|
||||
type: 'GET',
|
||||
data: {
|
||||
phoneCountryCode: self.phoneCountryCodeInput.getComponent(cc.EditBox).string,
|
||||
phoneNum: self.phoneNumberInput.getComponent(cc.EditBox).string
|
||||
},
|
||||
success: function(res) {
|
||||
switch (res.ret) {
|
||||
case constants.RET_CODE.OK:
|
||||
self.phoneNumberTips.getComponent(cc.Label).string = '';
|
||||
self.captchaTips.getComponent(cc.Label).string = '';
|
||||
break;
|
||||
case constants.RET_CODE.DUPLICATED:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.DUPLICATED");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_PHONE_COUNTRY_CODE:
|
||||
case constants.RET_CODE.INCORRECT_PHONE_NUMBER:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
break;
|
||||
case constants.RET_CODE.IS_TEST_ACC:
|
||||
self.smsLoginCaptchaInput.getComponent(cc.EditBox).string = res.smsLoginCaptcha;
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.TEST_USER");
|
||||
timerEnable = false;
|
||||
// clearInterval(self.countdownTimer);
|
||||
break;
|
||||
case constants.RET_CODE.SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_FREEQUENT_REQUIRE");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (timerEnable)
|
||||
self.countdownTime(self);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
countdownTime(self) {
|
||||
self.smsLoginCaptchaButton.off('click', self.onSMSCaptchaGetButtonClicked);
|
||||
self.smsLoginCaptchaButton.removeChild(self.smsGetCaptchaNode);
|
||||
self.smsWaitCountdownNode.parent = self.smsLoginCaptchaButton;
|
||||
var total = 20; // Magic number
|
||||
self.countdownTimer = setInterval(function() {
|
||||
if (total === 0) {
|
||||
self.smsWaitCountdownNode.parent.removeChild(self.smsWaitCountdownNode);
|
||||
self.smsGetCaptchaNode.parent = self.smsLoginCaptchaButton;
|
||||
self.smsWaitCountdownNode.getChildByName('WaitTimeLabel').getComponent(cc.Label).string = 20;
|
||||
self.smsLoginCaptchaButton.on('click', self.onSMSCaptchaGetButtonClicked);
|
||||
clearInterval(self.countdownTimer);
|
||||
} else {
|
||||
total--;
|
||||
self.smsWaitCountdownNode.getChildByName('WaitTimeLabel').getComponent(cc.Label).string = total;
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
},
|
||||
|
||||
checkIntAuthTokenExpire() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!cc.sys.localStorage.getItem("selfPlayer")) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
(selfPlayer.intAuthToken && new Date().getTime() < selfPlayer.expiresAt) ? resolve() : reject();
|
||||
})
|
||||
},
|
||||
|
||||
checkPhoneNumber(type) {
|
||||
const self = this;
|
||||
const phoneNumberRegexp = self.regexList.PHONE;
|
||||
var phoneNumberString = self.phoneNumberInput.getComponent(cc.EditBox).string;
|
||||
if (phoneNumberString) {
|
||||
return true;
|
||||
if (!phoneNumberRegexp.test(phoneNumberString)) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (type === 'getCaptcha' || type === 'login') {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.PHONE_ERR");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
checkCaptcha(type) {
|
||||
const self = this;
|
||||
const captchaRegexp = self.regexList.SMS_CAPTCHA_CODE;
|
||||
var captchaString = self.smsLoginCaptchaInput.getComponent(cc.EditBox).string;
|
||||
|
||||
if (captchaString) {
|
||||
if (self.smsLoginCaptchaInput.getComponent(cc.EditBox).string.length !== 4 || (!captchaRegexp.test(captchaString))) {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.CAPTCHA_ERR");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (type === 'login') {
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.CAPTCHA_ERR");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
useTokenLogin(_intAuthToken) {
|
||||
var self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.INT_AUTH_TOKEN + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
intAuthToken: _intAuthToken
|
||||
},
|
||||
success: function(resp) {
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `useTokenLogin` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
timeout: function() {
|
||||
self.enableInteractiveControls(true);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
enableInteractiveControls(enabled) {},
|
||||
|
||||
onLoginButtonClicked(evt) {
|
||||
const self = this;
|
||||
if (!self.checkPhoneNumber('login') || !self.checkCaptcha('login')) {
|
||||
return;
|
||||
}
|
||||
self.loginParams = {
|
||||
phoneCountryCode: self.phoneCountryCodeInput.getComponent(cc.EditBox).string,
|
||||
phoneNum: self.phoneNumberInput.getComponent(cc.EditBox).string,
|
||||
smsLoginCaptcha: self.smsLoginCaptchaInput.getComponent(cc.EditBox).string
|
||||
};
|
||||
self.enableInteractiveControls(false);
|
||||
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER +
|
||||
constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.SMS_CAPTCHA + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: self.loginParams,
|
||||
success: function(resp) {
|
||||
self.onLoggedIn(resp);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage()
|
||||
},
|
||||
timeout: function() {
|
||||
self.enableInteractiveControls(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
onWechatLoggedIn(res) {
|
||||
const self = this;
|
||||
if (constants.RET_CODE.OK == res.ret) {
|
||||
//根据服务器返回信息设置selfPlayer
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
displayName: res.displayName,
|
||||
avatar: res.avatar,
|
||||
}
|
||||
cc.sys.localStorage.setItem('selfPlayer', JSON.stringify(selfPlayer));
|
||||
|
||||
self.useTokenLogin(res.intAuthToken);
|
||||
} else {
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorCode = " + res.ret);
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
},
|
||||
|
||||
onLoggedIn(res) {
|
||||
const self = this;
|
||||
console.log("OnLoggedIn: ", res);
|
||||
if (constants.RET_CODE.OK == res.ret) {
|
||||
if (window.isUsingX5BlinkKernelOrWebkitWeChatKernel()) {
|
||||
window.initWxSdk = self.initWxSdk.bind(self);
|
||||
window.initWxSdk();
|
||||
}
|
||||
self.enableInteractiveControls(false);
|
||||
const date = Number(res.expiresAt);
|
||||
const selfPlayer = {
|
||||
expiresAt: date,
|
||||
playerId: res.playerId,
|
||||
intAuthToken: res.intAuthToken,
|
||||
avatar: res.avatar,
|
||||
displayName: res.displayName,
|
||||
name: res.name,
|
||||
}
|
||||
cc.sys.localStorage.setItem("selfPlayer", JSON.stringify(selfPlayer));
|
||||
console.log("cc.sys.localStorage.selfPlayer = ", cc.sys.localStorage.getItem("selfPlayer"));
|
||||
if (self.countdownTimer) {
|
||||
clearInterval(self.countdownTimer);
|
||||
}
|
||||
|
||||
cc.director.loadScene('default_map');
|
||||
} else {
|
||||
console.warn('onLoggedIn failed!')
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.enableInteractiveControls(true);
|
||||
switch (res.ret) {
|
||||
case constants.RET_CODE.DUPLICATED:
|
||||
this.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.DUPLICATED");
|
||||
break;
|
||||
case constants.RET_CODE.TOKEN_EXPIRED:
|
||||
this.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.LOGIN_TOKEN_EXPIRED");
|
||||
break;
|
||||
case constants.RET_CODE.SMS_CAPTCHA_NOT_MATCH:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_CAPTCHA:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case constants.RET_CODE.SMS_CAPTCHA_CODE_NOT_EXISTING:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.SMS_CAPTCHA_NOT_MATCH");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_PHONE_NUMBER:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
case constants.RET_CODE.INVALID_REQUEST_PARAM:
|
||||
self.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
case constants.RET_CODE.INCORRECT_PHONE_COUNTRY_CODE:
|
||||
case constants.RET_CODE.INCORRECT_PHONE_NUMBER:
|
||||
this.captchaTips.getComponent(cc.Label).string = i18n.t("login.tips.INCORRECT_PHONE_NUMBER");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
self.showTips(i18n.t("login.tips.AUTO_LOGIN_FAILED_WILL_USE_MANUAL_LOGIN"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
}
|
||||
},
|
||||
|
||||
useWXCodeLogin(_code) {
|
||||
const self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
code: _code
|
||||
},
|
||||
success: function(res) {
|
||||
self.onWechatLoggedIn(res);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorMsg =" + errMsg);
|
||||
},
|
||||
timeout: function() {
|
||||
console.log("Login attempt `onLoginButtonClicked` timed out, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorMsg =" + errMsg);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 对比useWxCodeLogin函数只是请求了不同url
|
||||
useWxCodeMiniGameLogin(_code, _userInfo) {
|
||||
const self = this;
|
||||
NetworkUtils.ajax({
|
||||
url: backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHATGAME + constants.ROUTE_PATH.LOGIN,
|
||||
type: "POST",
|
||||
data: {
|
||||
code: _code,
|
||||
avatarUrl: _userInfo.avatarUrl,
|
||||
nickName: _userInfo.nickName,
|
||||
},
|
||||
success: function(res) {
|
||||
self.onWechatLoggedIn(res);
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY") + ", errorMsg =" + errMsg);
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
timeout: function() {
|
||||
console.log("Login attempt `onLoginButtonClicked` failed, about to execute `clearBoundRoomIdInBothVolatileAndPersistentStorage`.");
|
||||
cc.sys.localStorage.removeItem("selfPlayer");
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
self.showTips(i18n.t("login.tips.WECHAT_LOGIN_FAILED_TAP_SCREEN_TO_RETRY"));
|
||||
self.createAuthorizeThenLoginButton();
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getWechatCode(evt) {
|
||||
let self = this;
|
||||
self.showTips("");
|
||||
const wechatServerEndpoint = wechatAddress.PROTOCOL + "://" + wechatAddress.HOST + ((null != wechatAddress.PORT && "" != wechatAddress.PORT.trim()) ? (":" + wechatAddress.PORT) : "");
|
||||
const url = wechatServerEndpoint + constants.WECHAT.AUTHORIZE_PATH + "?" + wechatAddress.APPID_LITERAL + "&" + constants.WECHAT.REDIRECT_RUI_KEY + NetworkUtils.encode(window.location.href) + "&" + constants.WECHAT.RESPONSE_TYPE + "&" + constants.WECHAT.SCOPE + constants.WECHAT.FIN;
|
||||
console.log("To visit wechat auth addr: ", url);
|
||||
window.location.href = url;
|
||||
},
|
||||
|
||||
initWxSdk() {
|
||||
const selfPlayer = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
||||
const origUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
/*
|
||||
* The `shareLink` must
|
||||
* - have its 2nd-order-domain registered as trusted 2nd-order under the targetd `res.jsConfig.app_id`, and
|
||||
* - extracted from current window.location.href.
|
||||
*/
|
||||
const shareLink = origUrl;
|
||||
const updateAppMsgShareDataObj = {
|
||||
type: 'link', // 分享类型,music、video或link,不填默认为link
|
||||
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
|
||||
title: document.title, // 分享标题
|
||||
desc: 'Let\'s play together!', // 分享描述
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {
|
||||
// 设置成功
|
||||
}
|
||||
};
|
||||
const menuShareTimelineObj = {
|
||||
title: document.title, // 分享标题
|
||||
link: shareLink + (cc.sys.localStorage.getItem('boundRoomId') ? "" : ("?expectedRoomId=" + cc.sys.localStorage.getItem('boundRoomId'))),
|
||||
imgUrl: origUrl + "/favicon.ico", // 分享图标
|
||||
success: function() {}
|
||||
};
|
||||
|
||||
const wxConfigUrl = (window.isUsingWebkitWechatKernel() ? window.atFirstLocationHref : window.location.href);
|
||||
|
||||
//接入微信登录接口
|
||||
NetworkUtils.ajax({
|
||||
"url": backendAddress.PROTOCOL + '://' + backendAddress.HOST + ':' + backendAddress.PORT + constants.ROUTE_PATH.API + constants.ROUTE_PATH.PLAYER + constants.ROUTE_PATH.VERSION + constants.ROUTE_PATH.WECHAT + constants.ROUTE_PATH.JSCONFIG,
|
||||
type: "POST",
|
||||
data: {
|
||||
"url": wxConfigUrl,
|
||||
"intAuthToken": selfPlayer.intAuthToken,
|
||||
},
|
||||
success: function(res) {
|
||||
if (constants.RET_CODE.OK != res.ret) {
|
||||
console.warn("Failed to get `wsConfig`: ", res);
|
||||
return;
|
||||
}
|
||||
const jsConfig = res.jsConfig;
|
||||
const configData = {
|
||||
debug: CC_DEBUG, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
||||
appId: jsConfig.app_id, // 必填,公众号的唯一标识
|
||||
timestamp: jsConfig.timestamp.toString(), // 必填,生成签名的时间戳
|
||||
nonceStr: jsConfig.nonce_str, // 必填,生成签名的随机串
|
||||
jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline'],
|
||||
signature: jsConfig.signature, // 必填,签名
|
||||
};
|
||||
console.log("config url: ", wxConfigUrl);
|
||||
console.log("wx.config: ", configData);
|
||||
wx.config(configData);
|
||||
console.log("Current window.location.href: ", window.location.href);
|
||||
wx.ready(function() {
|
||||
console.log("Here is wx.ready.")
|
||||
wx.onMenuShareAppMessage(updateAppMsgShareDataObj);
|
||||
wx.onMenuShareTimeline(menuShareTimelineObj);
|
||||
});
|
||||
wx.error(function(res) {
|
||||
console.error("wx config fails and error is ", JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
error: function(xhr, status, errMsg) {
|
||||
console.error("Failed to get `wsConfig`: ", errMsg);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
const self = this;
|
||||
if (null != wxDownloader && 0 < wxDownloader.totalBytesExpectedToWriteForAllTasks) {
|
||||
self.writtenBytes.string = wxDownloader.totalBytesWrittenForAllTasks;
|
||||
self.expectedToWriteBytes.string = wxDownloader.totalBytesExpectedToWriteForAllTasks;
|
||||
self.downloadProgress.progress = 1.0*wxDownloader.totalBytesWrittenForAllTasks/wxDownloader.totalBytesExpectedToWriteForAllTasks;
|
||||
}
|
||||
const totalUrlsToHandle = (wxDownloader.immediateHandleItemCount + wxDownloader.immediateReadFromLocalCount + wxDownloader.immediatePackDownloaderCount);
|
||||
const totalUrlsHandled = (wxDownloader.immediateHandleItemCompleteCount + wxDownloader.immediateReadFromLocalCompleteCount + wxDownloader.immediatePackDownloaderCompleteCount);
|
||||
if (null != wxDownloader && 0 < totalUrlsToHandle) {
|
||||
self.handledUrlsCount.string = totalUrlsHandled;
|
||||
self.toHandledUrlsCount.string = totalUrlsToHandle;
|
||||
self.handlerProgress.progress = 1.0*totalUrlsHandled/totalUrlsToHandle;
|
||||
}
|
||||
}
|
||||
});
|
@@ -1,10 +1,18 @@
|
||||
const RingBuffer = require('./RingBuffer');
|
||||
|
||||
window.UPSYNC_MSG_ACT_HB_PING = 1;
|
||||
window.UPSYNC_MSG_ACT_PLAYER_CMD = 2;
|
||||
window.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK = 3;
|
||||
|
||||
window.DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED = -98;
|
||||
window.DOWNSYNC_MSG_ACT_PLAYER_READDED_AND_ACKED = -97;
|
||||
window.DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START = -1;
|
||||
window.DOWNSYNC_MSG_ACT_BATTLE_START = 0;
|
||||
window.DOWNSYNC_MSG_ACT_HB_REQ = 1;
|
||||
window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
|
||||
window.DOWNSYNC_MSG_ACT_ROOM_FRAME = 3;
|
||||
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
|
||||
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
|
||||
|
||||
|
||||
window.sendSafely = function(msgStr) {
|
||||
/**
|
||||
@@ -74,8 +82,6 @@ function _base64ToUint8Array(base64) {
|
||||
origBytes[i] = origBinaryStr.charCodeAt(i);
|
||||
}
|
||||
return origBytes;
|
||||
} else if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
return Buffer.from(base64, 'base64');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -86,34 +92,18 @@ function _base64ToArrayBuffer(base64) {
|
||||
}
|
||||
|
||||
window.getExpectedRoomIdSync = function() {
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
return window.expectedRoomId;
|
||||
const qDict = window.getQueryParamDict();
|
||||
if (qDict) {
|
||||
return qDict["expectedRoomId"];
|
||||
} else {
|
||||
const qDict = window.getQueryParamDict();
|
||||
if (qDict) {
|
||||
return qDict["expectedRoomId"];
|
||||
} else {
|
||||
if (window.history && window.history.state) {
|
||||
return window.history.state.expectedRoomId;
|
||||
}
|
||||
if (window.history && window.history.state) {
|
||||
return window.history.state.expectedRoomId;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
window.unsetClientSessionCloseOrErrorFlag = function() {
|
||||
cc.sys.localStorage.removeItem("ClientSessionCloseOrErrorFlag");
|
||||
return;
|
||||
}
|
||||
|
||||
window.setClientSessionCloseOrErrorFlag = function() {
|
||||
const oldVal = cc.sys.localStorage.getItem("ClientSessionCloseOrErrorFlag");
|
||||
if (true == oldVal) return false;
|
||||
cc.sys.localStorage.setItem("ClientSessionCloseOrErrorFlag", true);
|
||||
return true;
|
||||
}
|
||||
|
||||
window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
||||
if (window.clientSession && window.clientSession.readyState == WebSocket.OPEN) {
|
||||
if (null != onopenCb) {
|
||||
@@ -122,17 +112,15 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const intAuthToken = cc.sys.localStorage.getItem("selfPlayer") ? JSON.parse(cc.sys.localStorage.getItem('selfPlayer')).intAuthToken : "";
|
||||
const selfPlayerStr = cc.sys.localStorage.getItem("selfPlayer");
|
||||
const selfPlayer = null == selfPlayerStr ? null : JSON.parse(selfPlayerStr);
|
||||
const intAuthToken = null == selfPlayer ? "" : selfPlayer.intAuthToken;
|
||||
|
||||
let urlToConnect = backendAddress.PROTOCOL.replace('http', 'ws') + '://' + backendAddress.HOST + ":" + backendAddress.PORT + backendAddress.WS_PATH_PREFIX + "?intAuthToken=" + intAuthToken;
|
||||
|
||||
if (null != expectedRoomId) {
|
||||
console.log("initPersistentSessionClient with expectedRoomId == " + expectedRoomId);
|
||||
urlToConnect = urlToConnect + "&expectedRoomId=" + expectedRoomId;
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
// This is a dirty hack. -- YFLu
|
||||
window.expectedRoomId = null;
|
||||
}
|
||||
} else {
|
||||
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
||||
if (null != window.boundRoomId) {
|
||||
@@ -143,90 +131,108 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
||||
|
||||
const currentHistoryState = window.history && window.history.state ? window.history.state : {};
|
||||
|
||||
if (cc.sys.platform != cc.sys.WECHAT_GAME) {
|
||||
window.history.replaceState(currentHistoryState, document.title, window.location.pathname);
|
||||
}
|
||||
|
||||
const clientSession = new WebSocket(urlToConnect);
|
||||
clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
|
||||
|
||||
clientSession.onopen = function(event) {
|
||||
console.log("The WS clientSession is opened.");
|
||||
clientSession.onopen = function(evt) {
|
||||
console.log("The WS clientSession is opened. clientSession.id=", clientSession.id);
|
||||
window.clientSession = clientSession;
|
||||
if (null == onopenCb) return;
|
||||
onopenCb();
|
||||
};
|
||||
|
||||
clientSession.onmessage = function(event) {
|
||||
if (null == event || null == event.data) {
|
||||
clientSession.onmessage = function(evt) {
|
||||
if (null == evt || null == evt.data) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const resp = window.WsResp.decode(new Uint8Array(event.data));
|
||||
const resp = window.WsResp.decode(new Uint8Array(evt.data));
|
||||
switch (resp.act) {
|
||||
case window.DOWNSYNC_MSG_ACT_HB_REQ:
|
||||
window.handleHbRequirements(resp); // 获取boundRoomId并存储到localStorage
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_ROOM_FRAME:
|
||||
if (window.handleRoomDownsyncFrame) {
|
||||
window.handleRoomDownsyncFrame(resp.rdf);
|
||||
}
|
||||
case window.DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED:
|
||||
mapIns.onPlayerAdded(resp.rdf);
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_PLAYER_READDED_AND_ACKED:
|
||||
// Deliberately left blank for now
|
||||
mapIns.hideFindingPlayersGUI();
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START:
|
||||
mapIns.onBattleReadyToStart(resp.rdf.playerMetas);
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_BATTLE_START:
|
||||
mapIns.onRoomDownsyncFrame(resp.rdf);
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED:
|
||||
mapIns.onBattleStopped();
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_INPUT_BATCH:
|
||||
if (window.handleInputFrameDownsyncBatch) {
|
||||
window.handleInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
|
||||
mapIns.onInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
|
||||
break;
|
||||
case window.DOWNSYNC_MSG_ACT_FORCED_RESYNC:
|
||||
if (null == resp.inputFrameDownsyncBatch || 0 >= resp.inputFrameDownsyncBatch.length) {
|
||||
console.error("Got empty inputFrameDownsyncBatch upon resync@localRenderFrameId=", mapIns.renderFrameId, ", @lastAllConfirmedRenderFrameId=", mapIns.lastAllConfirmedRenderFrameId, "@lastAllConfirmedInputFrameId=", mapIns.lastAllConfirmedInputFrameId, ", @localRecentInputCache=", mapIns._stringifyRecentInputCache(false), ", the incoming resp=\n", JSON.stringify(resp, null, 2));
|
||||
return;
|
||||
}
|
||||
// Unless upon ws session lost and reconnected, it's maintained true that "inputFrameDownsyncBatch[0].inputFrameId == frontend.lastAllConfirmedInputFrameId+1", and in this case we should try to keep frontend moving only by "frontend.recentInputCache" to avoid jiggling of synced positions
|
||||
const inputFrameIdConsecutive = (resp.inputFrameDownsyncBatch[0].inputFrameId == mapIns.lastAllConfirmedInputFrameId + 1);
|
||||
const renderFrameIdConsecutive = (resp.rdf.id <= mapIns.renderFrameId + mapIns.renderFrameIdLagTolerance);
|
||||
if (inputFrameIdConsecutive && renderFrameIdConsecutive) {
|
||||
// console.log("Got consecutive resync@localRenderFrameId=", mapIns.renderFrameId, ", @lastAllConfirmedRenderFrameId=", mapIns.lastAllConfirmedRenderFrameId, "@lastAllConfirmedInputFrameId=", mapIns.lastAllConfirmedInputFrameId, ", @localRecentInputCache=", mapIns._stringifyRecentInputCache(false), ", the incoming resp=\n", JSON.stringify(resp));
|
||||
mapIns.onInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
|
||||
} else {
|
||||
// console.warn("Got forced resync@localRenderFrameId=", mapIns.renderFrameId, ", @lastAllConfirmedRenderFrameId=", mapIns.lastAllConfirmedRenderFrameId, "@lastAllConfirmedInputFrameId=", mapIns.lastAllConfirmedInputFrameId, ", @localRecentInputCache=", mapIns._stringifyRecentInputCache(false), ", the incoming resp=\n", JSON.stringify(resp, null, 2));
|
||||
console.warn("Got forced resync@localRenderFrameId=", mapIns.renderFrameId, ", @lastAllConfirmedRenderFrameId=", mapIns.lastAllConfirmedRenderFrameId, "@lastAllConfirmedInputFrameId=", mapIns.lastAllConfirmedInputFrameId, ", @localRecentInputCache=", mapIns._stringifyRecentInputCache(false), ", inputFrameIdConsecutive=", inputFrameIdConsecutive, ", renderFrameIdConsecutive=", renderFrameIdConsecutive);
|
||||
// The following order of execution is important
|
||||
mapIns.onRoomDownsyncFrame(resp.rdf);
|
||||
mapIns.onInputFrameDownsyncBatch(resp.inputFrameDownsyncBatch);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Unexpected error when parsing data of:", event.data, e);
|
||||
console.error("Unexpected error when parsing data of:", evt.data, e);
|
||||
}
|
||||
};
|
||||
|
||||
clientSession.onerror = function(event) {
|
||||
if (!window.setClientSessionCloseOrErrorFlag()) {
|
||||
return;
|
||||
clientSession.onerror = function(evt) {
|
||||
console.error("Error caught on the WS clientSession: ", evt);
|
||||
if (window.handleClientSessionError) {
|
||||
window.handleClientSessionError();
|
||||
}
|
||||
console.error("Error caught on the WS clientSession: ", event);
|
||||
if (window.clientSessionPingInterval) {
|
||||
clearInterval(window.clientSessionPingInterval);
|
||||
}
|
||||
if (window.handleClientSessionCloseOrError) {
|
||||
window.handleClientSessionCloseOrError();
|
||||
}
|
||||
window.unsetClientSessionCloseOrErrorFlag();
|
||||
};
|
||||
|
||||
clientSession.onclose = function(event) {
|
||||
if (!window.setClientSessionCloseOrErrorFlag()) {
|
||||
return;
|
||||
}
|
||||
console.warn("The WS clientSession is closed: ", event);
|
||||
if (window.clientSessionPingInterval) {
|
||||
clearInterval(window.clientSessionPingInterval);
|
||||
}
|
||||
if (false == event.wasClean) {
|
||||
// Chrome doesn't allow the use of "CustomCloseCode"s (yet) and will callback with a "WebsocketStdCloseCode 1006" and "false == event.wasClean" here. See https://tools.ietf.org/html/rfc6455#section-7.4 for more information.
|
||||
if (window.handleClientSessionCloseOrError) {
|
||||
window.handleClientSessionCloseOrError();
|
||||
clientSession.onclose = function(evt) {
|
||||
// [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
|
||||
console.warn("The WS clientSession is closed: ", evt, clientSession);
|
||||
if (false == evt.wasClean) {
|
||||
/*
|
||||
Chrome doesn't allow the use of "CustomCloseCode"s (yet) and will callback with a "WebsocketStdCloseCode 1006" and "false == evt.wasClean" here. See https://tools.ietf.org/html/rfc6455#section-7.4 for more information.
|
||||
*/
|
||||
if (window.handleClientSessionError) {
|
||||
window.handleClientSessionError();
|
||||
}
|
||||
} else {
|
||||
switch (event.code) {
|
||||
switch (evt.code) {
|
||||
case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM:
|
||||
case constants.RET_CODE.PLAYER_NOT_READDABLE_TO_ROOM:
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
break;
|
||||
case constants.RET_CODE.UNKNOWN_ERROR:
|
||||
case constants.RET_CODE.MYSQL_ERROR:
|
||||
case constants.RET_CODE.PLAYER_NOT_FOUND:
|
||||
case constants.RET_CODE.PLAYER_CHEATING:
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
case 1006: // Peer(i.e. the backend) gone unexpectedly
|
||||
if (window.handleClientSessionError) {
|
||||
window.handleClientSessionError();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (window.handleClientSessionCloseOrError) {
|
||||
window.handleClientSessionCloseOrError();
|
||||
}
|
||||
}
|
||||
window.unsetClientSessionCloseOrErrorFlag();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -237,27 +243,23 @@ window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdIn
|
||||
window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
|
||||
}
|
||||
/**
|
||||
* Here I deliberately removed the callback in the "common `handleClientSessionCloseOrError` callback"
|
||||
* Here I deliberately removed the callback in the "common `handleClientSessionError` callback"
|
||||
* within which another invocation to `clearLocalStorageAndBackToLoginScene` will be made.
|
||||
*
|
||||
* It'll be re-assigned to the common one upon reentrance of `Map.onLoad`.
|
||||
*
|
||||
* -- YFLu 2019-04-06
|
||||
*/
|
||||
window.handleClientSessionCloseOrError = () => {
|
||||
console.warn("+++++++ Special handleClientSessionCloseOrError() assigned within `clearLocalStorageAndBackToLoginScene`");
|
||||
window.handleClientSessionError = () => {
|
||||
console.warn("+++++++ Special handleClientSessionError() assigned within `clearLocalStorageAndBackToLoginScene`");
|
||||
// TBD.
|
||||
window.handleClientSessionCloseOrError = null; // To ensure that it's called at most once.
|
||||
window.handleClientSessionError = null; // To ensure that it's called at most once.
|
||||
};
|
||||
window.closeWSConnection();
|
||||
window.clearSelfPlayer();
|
||||
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||
}
|
||||
if (cc.sys.platform == cc.sys.WECHAT_GAME) {
|
||||
cc.director.loadScene('wechatGameLogin');
|
||||
} else {
|
||||
cc.director.loadScene('login');
|
||||
}
|
||||
cc.director.loadScene('login');
|
||||
};
|
||||
|
||||
|