├── .gitignore ├── README.md ├── assets ├── components.meta ├── components │ ├── joystick.meta │ └── joystick │ │ ├── Joystick.prefab │ │ ├── Joystick.prefab.meta │ │ ├── Joystick.ts │ │ ├── Joystick.ts.meta │ │ ├── background.png │ │ ├── background.png.meta │ │ ├── center.png │ │ └── center.png.meta ├── res.meta ├── res │ ├── test.fire │ └── test.fire.meta ├── src.meta └── src │ ├── TestScene.ts │ └── TestScene.ts.meta ├── creator.d.ts ├── joystick.gif ├── joystick2.png ├── jsconfig.json ├── nextui-joystick.zip ├── project.json └── settings └── project.json /.gitignore: -------------------------------------------------------------------------------- 1 | #///////////////////////////////////////////////////////////////////////////// 2 | # Fireball Projects 3 | #///////////////////////////////////////////////////////////////////////////// 4 | 5 | library/ 6 | temp/ 7 | local/ 8 | build/ 9 | 10 | #///////////////////////////////////////////////////////////////////////////// 11 | # Logs and databases 12 | #///////////////////////////////////////////////////////////////////////////// 13 | 14 | *.log 15 | *.sql 16 | *.sqlite 17 | 18 | #///////////////////////////////////////////////////////////////////////////// 19 | # files for debugger 20 | #///////////////////////////////////////////////////////////////////////////// 21 | 22 | *.sln 23 | *.csproj 24 | *.pidb 25 | *.unityproj 26 | *.suo 27 | 28 | #///////////////////////////////////////////////////////////////////////////// 29 | # OS generated files 30 | #///////////////////////////////////////////////////////////////////////////// 31 | 32 | .DS_Store 33 | ehthumbs.db 34 | Thumbs.db 35 | 36 | #///////////////////////////////////////////////////////////////////////////// 37 | # exvim files 38 | #///////////////////////////////////////////////////////////////////////////// 39 | 40 | *UnityVS.meta 41 | *.err 42 | *.err.meta 43 | *.exvim 44 | *.exvim.meta 45 | *.vimentry 46 | *.vimentry.meta 47 | *.vimproject 48 | *.vimproject.meta 49 | .vimfiles.*/ 50 | .exvim.*/ 51 | quick_gen_project_*_autogen.bat 52 | quick_gen_project_*_autogen.bat.meta 53 | quick_gen_project_*_autogen.sh 54 | quick_gen_project_*_autogen.sh.meta 55 | .exvim.app 56 | 57 | #///////////////////////////////////////////////////////////////////////////// 58 | # webstorm files 59 | #///////////////////////////////////////////////////////////////////////////// 60 | 61 | .idea/ 62 | 63 | #////////////////////////// 64 | # VS Code 65 | #////////////////////////// 66 | 67 | .vscode/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Joystick 2 | 通用摇杆组件,固定位置或范围内可移动位置,事件绑定。 3 | # 用法 4 | 5 | 1.将 **Joystick** 预制体拖入场景,调整背景大小用于限制点击范围,调整后将背景图片隐藏 6 | 7 | 2.绑定事件到对应脚本内的函数 8 | 9 | ![](./joystick2.png) 10 | 11 | 示例: 12 | 13 | ``` 14 | import { JoystickEvent, Joystick } from "../components/joystick/Joystick"; 15 | 16 | const { ccclass, property } = cc._decorator; 17 | 18 | @ccclass 19 | export class TestScene extends cc.Component { 20 | 21 | @property(cc.Node) 22 | private playerNode: cc.Node = null; 23 | @property(cc.Integer) 24 | private speed: number = 300; 25 | 26 | private moveDirVec: cc.Vec2 = cc.v2(); 27 | 28 | handleMove(event: JoystickEvent) { 29 | this.moveDirVec = Joystick.GetDirVecByDir(event.newDir); 30 | } 31 | 32 | update(dt: number) { 33 | let distance = this.speed * dt; 34 | let moveVec = this.moveDirVec.mul(distance); 35 | this.playerNode.position = this.playerNode.position.add(moveVec); 36 | } 37 | 38 | } 39 | ``` 40 | # 预览 41 | ![](./joystick.gif) 42 | -------------------------------------------------------------------------------- /assets/components.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "52601631-dc9a-4f69-9174-cf0b8386b53a", 4 | "isSubpackage": false, 5 | "subpackageName": "", 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /assets/components/joystick.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "6ce33b21-4e37-43cb-9f97-04b3c6efccd5", 4 | "isSubpackage": false, 5 | "subpackageName": "", 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /assets/components/joystick/Joystick.prefab: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "__type__": "cc.Prefab", 4 | "_name": "", 5 | "_objFlags": 0, 6 | "_native": "", 7 | "data": { 8 | "__id__": 1 9 | }, 10 | "optimizationPolicy": 0, 11 | "asyncLoadAssets": false 12 | }, 13 | { 14 | "__type__": "cc.Node", 15 | "_name": "Joystick", 16 | "_objFlags": 0, 17 | "_parent": null, 18 | "_children": [ 19 | { 20 | "__id__": 2 21 | } 22 | ], 23 | "_active": true, 24 | "_level": 1, 25 | "_components": [ 26 | { 27 | "__id__": 8 28 | }, 29 | { 30 | "__id__": 9 31 | } 32 | ], 33 | "_prefab": { 34 | "__id__": 10 35 | }, 36 | "_opacity": 255, 37 | "_color": { 38 | "__type__": "cc.Color", 39 | "r": 255, 40 | "g": 255, 41 | "b": 255, 42 | "a": 255 43 | }, 44 | "_contentSize": { 45 | "__type__": "cc.Size", 46 | "width": 640, 47 | "height": 720 48 | }, 49 | "_anchorPoint": { 50 | "__type__": "cc.Vec2", 51 | "x": 0.5, 52 | "y": 0.5 53 | }, 54 | "_position": { 55 | "__type__": "cc.Vec3", 56 | "x": -320, 57 | "y": 0, 58 | "z": 0 59 | }, 60 | "_scale": { 61 | "__type__": "cc.Vec3", 62 | "x": 1, 63 | "y": 1, 64 | "z": 1 65 | }, 66 | "_rotationX": 0, 67 | "_rotationY": 0, 68 | "_quat": { 69 | "__type__": "cc.Quat", 70 | "x": 0, 71 | "y": 0, 72 | "z": 0, 73 | "w": 1 74 | }, 75 | "_skewX": 0, 76 | "_skewY": 0, 77 | "_zIndex": 0, 78 | "groupIndex": 0, 79 | "_id": "" 80 | }, 81 | { 82 | "__type__": "cc.Node", 83 | "_name": "background", 84 | "_objFlags": 0, 85 | "_parent": { 86 | "__id__": 1 87 | }, 88 | "_children": [ 89 | { 90 | "__id__": 3 91 | } 92 | ], 93 | "_active": true, 94 | "_level": 2, 95 | "_components": [ 96 | { 97 | "__id__": 6 98 | } 99 | ], 100 | "_prefab": { 101 | "__id__": 7 102 | }, 103 | "_opacity": 255, 104 | "_color": { 105 | "__type__": "cc.Color", 106 | "r": 255, 107 | "g": 255, 108 | "b": 255, 109 | "a": 255 110 | }, 111 | "_contentSize": { 112 | "__type__": "cc.Size", 113 | "width": 160, 114 | "height": 160 115 | }, 116 | "_anchorPoint": { 117 | "__type__": "cc.Vec2", 118 | "x": 0.5, 119 | "y": 0.5 120 | }, 121 | "_position": { 122 | "__type__": "cc.Vec3", 123 | "x": 0, 124 | "y": 0, 125 | "z": 0 126 | }, 127 | "_scale": { 128 | "__type__": "cc.Vec3", 129 | "x": 1, 130 | "y": 1, 131 | "z": 1 132 | }, 133 | "_rotationX": 0, 134 | "_rotationY": 0, 135 | "_quat": { 136 | "__type__": "cc.Quat", 137 | "x": 0, 138 | "y": 0, 139 | "z": 0, 140 | "w": 1 141 | }, 142 | "_skewX": 0, 143 | "_skewY": 0, 144 | "_zIndex": 0, 145 | "groupIndex": 0, 146 | "_id": "" 147 | }, 148 | { 149 | "__type__": "cc.Node", 150 | "_name": "bar", 151 | "_objFlags": 0, 152 | "_parent": { 153 | "__id__": 2 154 | }, 155 | "_children": [], 156 | "_active": true, 157 | "_level": 3, 158 | "_components": [ 159 | { 160 | "__id__": 4 161 | } 162 | ], 163 | "_prefab": { 164 | "__id__": 5 165 | }, 166 | "_opacity": 255, 167 | "_color": { 168 | "__type__": "cc.Color", 169 | "r": 255, 170 | "g": 255, 171 | "b": 255, 172 | "a": 255 173 | }, 174 | "_contentSize": { 175 | "__type__": "cc.Size", 176 | "width": 96, 177 | "height": 100 178 | }, 179 | "_anchorPoint": { 180 | "__type__": "cc.Vec2", 181 | "x": 0.5, 182 | "y": 0.5 183 | }, 184 | "_position": { 185 | "__type__": "cc.Vec3", 186 | "x": 0, 187 | "y": 0, 188 | "z": 0 189 | }, 190 | "_scale": { 191 | "__type__": "cc.Vec3", 192 | "x": 1, 193 | "y": 1, 194 | "z": 1 195 | }, 196 | "_rotationX": 0, 197 | "_rotationY": 0, 198 | "_quat": { 199 | "__type__": "cc.Quat", 200 | "x": 0, 201 | "y": 0, 202 | "z": 0, 203 | "w": 1 204 | }, 205 | "_skewX": 0, 206 | "_skewY": 0, 207 | "_zIndex": 0, 208 | "groupIndex": 0, 209 | "_id": "" 210 | }, 211 | { 212 | "__type__": "cc.Sprite", 213 | "_name": "", 214 | "_objFlags": 0, 215 | "node": { 216 | "__id__": 3 217 | }, 218 | "_enabled": true, 219 | "_srcBlendFactor": 770, 220 | "_dstBlendFactor": 771, 221 | "_spriteFrame": { 222 | "__uuid__": "94dcb3b8-3261-4606-86fc-9401c79d9b85" 223 | }, 224 | "_type": 0, 225 | "_sizeMode": 2, 226 | "_fillType": 0, 227 | "_fillCenter": { 228 | "__type__": "cc.Vec2", 229 | "x": 0, 230 | "y": 0 231 | }, 232 | "_fillStart": 0, 233 | "_fillRange": 0, 234 | "_isTrimmedMode": true, 235 | "_state": 0, 236 | "_atlas": null, 237 | "_id": "edxzaJDjtL9a4MRVzXPMzC" 238 | }, 239 | { 240 | "__type__": "cc.PrefabInfo", 241 | "root": { 242 | "__id__": 1 243 | }, 244 | "asset": { 245 | "__uuid__": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64" 246 | }, 247 | "fileId": "5fkVpIUdVHSq7coL/HTVxm", 248 | "sync": false 249 | }, 250 | { 251 | "__type__": "cc.Sprite", 252 | "_name": "", 253 | "_objFlags": 0, 254 | "node": { 255 | "__id__": 2 256 | }, 257 | "_enabled": true, 258 | "_srcBlendFactor": 770, 259 | "_dstBlendFactor": 771, 260 | "_spriteFrame": { 261 | "__uuid__": "bbcbdf54-2a7c-4ee2-8744-95e26cc7196e" 262 | }, 263 | "_type": 0, 264 | "_sizeMode": 2, 265 | "_fillType": 0, 266 | "_fillCenter": { 267 | "__type__": "cc.Vec2", 268 | "x": 0, 269 | "y": 0 270 | }, 271 | "_fillStart": 0, 272 | "_fillRange": 0, 273 | "_isTrimmedMode": true, 274 | "_state": 0, 275 | "_atlas": null, 276 | "_id": "d2W/4528tJpYIB3xL63FyL" 277 | }, 278 | { 279 | "__type__": "cc.PrefabInfo", 280 | "root": { 281 | "__id__": 1 282 | }, 283 | "asset": { 284 | "__uuid__": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64" 285 | }, 286 | "fileId": "44UOOWKsFPJZzHLlhNV4MU", 287 | "sync": false 288 | }, 289 | { 290 | "__type__": "cc.Sprite", 291 | "_name": "", 292 | "_objFlags": 0, 293 | "node": { 294 | "__id__": 1 295 | }, 296 | "_enabled": true, 297 | "_srcBlendFactor": 770, 298 | "_dstBlendFactor": 771, 299 | "_spriteFrame": { 300 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 301 | }, 302 | "_type": 0, 303 | "_sizeMode": 0, 304 | "_fillType": 0, 305 | "_fillCenter": { 306 | "__type__": "cc.Vec2", 307 | "x": 0, 308 | "y": 0 309 | }, 310 | "_fillStart": 0, 311 | "_fillRange": 0, 312 | "_isTrimmedMode": true, 313 | "_state": 0, 314 | "_atlas": null, 315 | "_id": "41m1bHrjtIELLVrMkIDzlF" 316 | }, 317 | { 318 | "__type__": "a962eBT4ohFNbE++6Onpd97", 319 | "_name": "", 320 | "_objFlags": 0, 321 | "node": { 322 | "__id__": 1 323 | }, 324 | "_enabled": true, 325 | "interactable": true, 326 | "fixed": true, 327 | "background": { 328 | "__id__": 2 329 | }, 330 | "bar": { 331 | "__id__": 3 332 | }, 333 | "moveEvents": [], 334 | "_id": "48VxYeCUROHoGC8VD8OWNP" 335 | }, 336 | { 337 | "__type__": "cc.PrefabInfo", 338 | "root": { 339 | "__id__": 1 340 | }, 341 | "asset": { 342 | "__uuid__": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64" 343 | }, 344 | "fileId": "92Mi75o4dIJbR3Ti0VtzYu", 345 | "sync": false 346 | } 347 | ] -------------------------------------------------------------------------------- /assets/components/joystick/Joystick.prefab.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.0", 3 | "uuid": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64", 4 | "optimizationPolicy": "AUTO", 5 | "asyncLoadAssets": false, 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /assets/components/joystick/Joystick.ts: -------------------------------------------------------------------------------- 1 | const { ccclass, property } = cc._decorator; 2 | 3 | export enum Direction { 4 | IDLE, LEFT, UP, RIGHT, DOWN, LEFT_UP, RIGHT_UP, LEFT_DOWN, RIGHT_DOWN 5 | } 6 | 7 | export interface JoystickEvent { 8 | oldDir: Direction; 9 | newDir: Direction; 10 | } 11 | 12 | @ccclass 13 | export class Joystick extends cc.Component { 14 | 15 | @property(cc.Boolean) 16 | private interactable = true; 17 | @property({ 18 | tooltip: '是否固定位置' 19 | }) 20 | private fixed = true; 21 | @property(cc.Node) 22 | private background: cc.Node = null; 23 | @property(cc.Node) 24 | private bar: cc.Node = null; 25 | @property([cc.Component.EventHandler]) 26 | private moveEvents: cc.Component.EventHandler[] = []; 27 | 28 | private radius: number; 29 | private _dirction = Direction.IDLE; 30 | private originPos: cc.Vec2; 31 | private get direction() { 32 | return this._dirction; 33 | } 34 | private set direction(newDir) { 35 | if (newDir === this.direction) return; 36 | cc.Component.EventHandler.emitEvents(this.moveEvents, { oldDir: this.direction, newDir: newDir }); 37 | this._dirction = newDir; 38 | } 39 | 40 | start() { 41 | this.radius = this.background.width / 2; 42 | this.direction = Direction.IDLE; 43 | this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); 44 | this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this); 45 | this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this); 46 | this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this); 47 | this.originPos = this.background.position; 48 | } 49 | 50 | private onTouchStart(event: cc.Event.EventTouch) { 51 | if (!this.interactable) return; 52 | if (!this.fixed) { 53 | this.background.position = this.node.convertToNodeSpaceAR(event.getLocation()); 54 | } else { 55 | this.onTouchMove(event); 56 | } 57 | } 58 | 59 | private onTouchMove(event: cc.Event.EventTouch) { 60 | if (!this.interactable) return; 61 | let localPos = this.background.convertToNodeSpaceAR(event.getLocation()); 62 | this.bar.position = localPos; 63 | let len = localPos.mag(); 64 | if (len > this.radius) { 65 | localPos.mulSelf(this.radius / len); 66 | } 67 | this.bar.position = localPos; 68 | let newDir = Joystick.GetDirctionByAngle(localPos.signAngle(cc.v2(-1, 0)) * 180 / Math.PI); 69 | this.direction = newDir; 70 | } 71 | 72 | private onTouchEnd() { 73 | if (!this.interactable) return; 74 | this.direction = Direction.IDLE; 75 | this.bar.position = cc.v2(); 76 | if (!this.fixed) { 77 | this.background.position = this.originPos; 78 | } 79 | } 80 | 81 | public static GetDirctionByAngle(angle: number) { 82 | if (angle >= -22.5 && angle < 22.5) { 83 | return Direction.LEFT; 84 | } else if (angle >= 22.5 && angle < 67.5) { 85 | return Direction.LEFT_UP; 86 | } else if (angle >= 67.5 && angle < 112.5) { 87 | return Direction.UP; 88 | } else if (angle >= 112.5 && angle < 157.5) { 89 | return Direction.RIGHT_UP; 90 | } else if (angle >= 157.5 || angle < - 157.5) { 91 | return Direction.RIGHT; 92 | } else if (angle >= -157.5 && angle < -112.5) { 93 | return Direction.RIGHT_DOWN; 94 | } else if (angle >= -112.5 && angle < -67.5) { 95 | return Direction.DOWN; 96 | } else if (angle >= -67.5 && angle < -22.5) { 97 | return Direction.LEFT_DOWN; 98 | } 99 | } 100 | 101 | public static GetDirVecByDir(dir: Direction) { 102 | switch (dir) { 103 | case Direction.LEFT: 104 | return cc.v2(-1, 0); 105 | case Direction.UP: 106 | return cc.v2(0, 1); 107 | case Direction.RIGHT: 108 | return cc.v2(1, 0); 109 | case Direction.DOWN: 110 | return cc.v2(0, -1); 111 | case Direction.LEFT_UP: 112 | return cc.v2(-1, 1).normalize(); 113 | case Direction.RIGHT_UP: 114 | return cc.v2(1, 1).normalize(); 115 | case Direction.RIGHT_DOWN: 116 | return cc.v2(1, -1).normalize(); 117 | case Direction.LEFT_DOWN: 118 | return cc.v2(-1, -1).normalize(); 119 | default: 120 | return cc.v2(); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /assets/components/joystick/Joystick.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.5", 3 | "uuid": "a962e053-e288-4535-b13e-fba3a7a5df7b", 4 | "isPlugin": false, 5 | "loadPluginInWeb": true, 6 | "loadPluginInNative": true, 7 | "loadPluginInEditor": false, 8 | "subMetas": {} 9 | } -------------------------------------------------------------------------------- /assets/components/joystick/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potato47/joystick/fa0102cac485456dc785b63abebc8323ceac348c/assets/components/joystick/background.png -------------------------------------------------------------------------------- /assets/components/joystick/background.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.2.0", 3 | "uuid": "45e4105d-592e-49bc-ab4b-ef4e169e9c80", 4 | "type": "sprite", 5 | "wrapMode": "clamp", 6 | "filterMode": "bilinear", 7 | "premultiplyAlpha": false, 8 | "subMetas": { 9 | "background": { 10 | "ver": "1.0.3", 11 | "uuid": "bbcbdf54-2a7c-4ee2-8744-95e26cc7196e", 12 | "rawTextureUuid": "45e4105d-592e-49bc-ab4b-ef4e169e9c80", 13 | "trimType": "auto", 14 | "trimThreshold": 1, 15 | "rotated": false, 16 | "offsetX": 0, 17 | "offsetY": 0, 18 | "trimX": 0, 19 | "trimY": 0, 20 | "width": 160, 21 | "height": 160, 22 | "rawWidth": 160, 23 | "rawHeight": 160, 24 | "borderTop": 0, 25 | "borderBottom": 0, 26 | "borderLeft": 0, 27 | "borderRight": 0, 28 | "subMetas": {} 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /assets/components/joystick/center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potato47/joystick/fa0102cac485456dc785b63abebc8323ceac348c/assets/components/joystick/center.png -------------------------------------------------------------------------------- /assets/components/joystick/center.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.2.0", 3 | "uuid": "5140b229-0163-49dc-bb81-73570f65ee09", 4 | "type": "sprite", 5 | "wrapMode": "clamp", 6 | "filterMode": "bilinear", 7 | "premultiplyAlpha": false, 8 | "subMetas": { 9 | "center": { 10 | "ver": "1.0.3", 11 | "uuid": "94dcb3b8-3261-4606-86fc-9401c79d9b85", 12 | "rawTextureUuid": "5140b229-0163-49dc-bb81-73570f65ee09", 13 | "trimType": "auto", 14 | "trimThreshold": 1, 15 | "rotated": false, 16 | "offsetX": 0, 17 | "offsetY": 0, 18 | "trimX": 0, 19 | "trimY": 0, 20 | "width": 96, 21 | "height": 100, 22 | "rawWidth": 96, 23 | "rawHeight": 100, 24 | "borderTop": 0, 25 | "borderBottom": 0, 26 | "borderLeft": 0, 27 | "borderRight": 0, 28 | "subMetas": {} 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /assets/res.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "bd44b5c2-6eb1-473b-8df6-a559225ae3c1", 4 | "isSubpackage": false, 5 | "subpackageName": "", 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /assets/res/test.fire: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "__type__": "cc.SceneAsset", 4 | "_name": "", 5 | "_objFlags": 0, 6 | "_native": "", 7 | "scene": { 8 | "__id__": 1 9 | } 10 | }, 11 | { 12 | "__type__": "cc.Scene", 13 | "_objFlags": 0, 14 | "_parent": null, 15 | "_children": [ 16 | { 17 | "__id__": 2 18 | } 19 | ], 20 | "_active": true, 21 | "_level": 0, 22 | "_components": [], 23 | "_prefab": null, 24 | "_opacity": 255, 25 | "_color": { 26 | "__type__": "cc.Color", 27 | "r": 255, 28 | "g": 255, 29 | "b": 255, 30 | "a": 255 31 | }, 32 | "_contentSize": { 33 | "__type__": "cc.Size", 34 | "width": 0, 35 | "height": 0 36 | }, 37 | "_anchorPoint": { 38 | "__type__": "cc.Vec2", 39 | "x": 0, 40 | "y": 0 41 | }, 42 | "_scale": { 43 | "__type__": "cc.Vec3", 44 | "x": 0.2713208654895345, 45 | "y": 0.2713208654895345, 46 | "z": 1 47 | }, 48 | "_quat": { 49 | "__type__": "cc.Quat", 50 | "x": 0, 51 | "y": 0, 52 | "z": 0, 53 | "w": 1 54 | }, 55 | "_zIndex": 0, 56 | "groupIndex": 0, 57 | "autoReleaseAssets": false, 58 | "_id": "ca3a401b-c4c3-4b35-addf-399f4198c930" 59 | }, 60 | { 61 | "__type__": "cc.Node", 62 | "_name": "Canvas", 63 | "_objFlags": 0, 64 | "_parent": { 65 | "__id__": 1 66 | }, 67 | "_children": [ 68 | { 69 | "__id__": 3 70 | }, 71 | { 72 | "__id__": 5 73 | }, 74 | { 75 | "__id__": 16 76 | } 77 | ], 78 | "_active": true, 79 | "_level": 1, 80 | "_components": [ 81 | { 82 | "__id__": 18 83 | }, 84 | { 85 | "__id__": 19 86 | } 87 | ], 88 | "_prefab": null, 89 | "_opacity": 255, 90 | "_color": { 91 | "__type__": "cc.Color", 92 | "r": 255, 93 | "g": 255, 94 | "b": 255, 95 | "a": 255 96 | }, 97 | "_contentSize": { 98 | "__type__": "cc.Size", 99 | "width": 1280, 100 | "height": 720 101 | }, 102 | "_anchorPoint": { 103 | "__type__": "cc.Vec2", 104 | "x": 0.5, 105 | "y": 0.5 106 | }, 107 | "_position": { 108 | "__type__": "cc.Vec3", 109 | "x": 640, 110 | "y": 360, 111 | "z": 0 112 | }, 113 | "_scale": { 114 | "__type__": "cc.Vec3", 115 | "x": 1, 116 | "y": 1, 117 | "z": 1 118 | }, 119 | "_rotationX": 0, 120 | "_rotationY": 0, 121 | "_quat": { 122 | "__type__": "cc.Quat", 123 | "x": 0, 124 | "y": 0, 125 | "z": 0, 126 | "w": 1 127 | }, 128 | "_skewX": 0, 129 | "_skewY": 0, 130 | "_zIndex": 0, 131 | "groupIndex": 0, 132 | "_id": "a02aMUJ8hElZrwp/rGpvCf" 133 | }, 134 | { 135 | "__type__": "cc.Node", 136 | "_name": "Main Camera", 137 | "_objFlags": 0, 138 | "_parent": { 139 | "__id__": 2 140 | }, 141 | "_children": [], 142 | "_active": true, 143 | "_level": 1, 144 | "_components": [ 145 | { 146 | "__id__": 4 147 | } 148 | ], 149 | "_prefab": null, 150 | "_opacity": 255, 151 | "_color": { 152 | "__type__": "cc.Color", 153 | "r": 255, 154 | "g": 255, 155 | "b": 255, 156 | "a": 255 157 | }, 158 | "_contentSize": { 159 | "__type__": "cc.Size", 160 | "width": 0, 161 | "height": 0 162 | }, 163 | "_anchorPoint": { 164 | "__type__": "cc.Vec2", 165 | "x": 0.5, 166 | "y": 0.5 167 | }, 168 | "_position": { 169 | "__type__": "cc.Vec3", 170 | "x": 0, 171 | "y": 0, 172 | "z": 0 173 | }, 174 | "_scale": { 175 | "__type__": "cc.Vec3", 176 | "x": 1, 177 | "y": 1, 178 | "z": 1 179 | }, 180 | "_rotationX": 0, 181 | "_rotationY": 0, 182 | "_quat": { 183 | "__type__": "cc.Quat", 184 | "x": 0, 185 | "y": 0, 186 | "z": 0, 187 | "w": 1 188 | }, 189 | "_skewX": 0, 190 | "_skewY": 0, 191 | "_zIndex": 0, 192 | "groupIndex": 0, 193 | "_id": "03yy40NqZJP6bq+4EUw3AK" 194 | }, 195 | { 196 | "__type__": "cc.Camera", 197 | "_name": "", 198 | "_objFlags": 0, 199 | "node": { 200 | "__id__": 3 201 | }, 202 | "_enabled": true, 203 | "_cullingMask": 4294967295, 204 | "_clearFlags": 7, 205 | "_backgroundColor": { 206 | "__type__": "cc.Color", 207 | "r": 0, 208 | "g": 0, 209 | "b": 0, 210 | "a": 255 211 | }, 212 | "_depth": -1, 213 | "_zoomRatio": 1, 214 | "_targetTexture": null, 215 | "_id": "22niyGAfhPW5d+/UYyS/wS" 216 | }, 217 | { 218 | "__type__": "cc.Node", 219 | "_name": "Joystick", 220 | "_objFlags": 0, 221 | "_parent": { 222 | "__id__": 2 223 | }, 224 | "_children": [ 225 | { 226 | "__id__": 6 227 | } 228 | ], 229 | "_active": true, 230 | "_level": 1, 231 | "_components": [ 232 | { 233 | "__id__": 12 234 | }, 235 | { 236 | "__id__": 13 237 | } 238 | ], 239 | "_prefab": { 240 | "__id__": 15 241 | }, 242 | "_opacity": 255, 243 | "_color": { 244 | "__type__": "cc.Color", 245 | "r": 255, 246 | "g": 255, 247 | "b": 255, 248 | "a": 255 249 | }, 250 | "_contentSize": { 251 | "__type__": "cc.Size", 252 | "width": 640, 253 | "height": 720 254 | }, 255 | "_anchorPoint": { 256 | "__type__": "cc.Vec2", 257 | "x": 0.5, 258 | "y": 0.5 259 | }, 260 | "_position": { 261 | "__type__": "cc.Vec3", 262 | "x": -320, 263 | "y": 0, 264 | "z": 0 265 | }, 266 | "_scale": { 267 | "__type__": "cc.Vec3", 268 | "x": 1, 269 | "y": 1, 270 | "z": 1 271 | }, 272 | "_rotationX": 0, 273 | "_rotationY": 0, 274 | "_quat": { 275 | "__type__": "cc.Quat", 276 | "x": 0, 277 | "y": 0, 278 | "z": 0, 279 | "w": 1 280 | }, 281 | "_skewX": 0, 282 | "_skewY": 0, 283 | "_zIndex": 0, 284 | "groupIndex": 0, 285 | "_id": "92Mi75o4dIJbR3Ti0VtzYu" 286 | }, 287 | { 288 | "__type__": "cc.Node", 289 | "_name": "background", 290 | "_objFlags": 0, 291 | "_parent": { 292 | "__id__": 5 293 | }, 294 | "_children": [ 295 | { 296 | "__id__": 7 297 | } 298 | ], 299 | "_active": true, 300 | "_level": 2, 301 | "_components": [ 302 | { 303 | "__id__": 10 304 | } 305 | ], 306 | "_prefab": { 307 | "__id__": 11 308 | }, 309 | "_opacity": 255, 310 | "_color": { 311 | "__type__": "cc.Color", 312 | "r": 255, 313 | "g": 255, 314 | "b": 255, 315 | "a": 255 316 | }, 317 | "_contentSize": { 318 | "__type__": "cc.Size", 319 | "width": 160, 320 | "height": 160 321 | }, 322 | "_anchorPoint": { 323 | "__type__": "cc.Vec2", 324 | "x": 0.5, 325 | "y": 0.5 326 | }, 327 | "_position": { 328 | "__type__": "cc.Vec3", 329 | "x": 0, 330 | "y": 0, 331 | "z": 0 332 | }, 333 | "_scale": { 334 | "__type__": "cc.Vec3", 335 | "x": 1, 336 | "y": 1, 337 | "z": 1 338 | }, 339 | "_rotationX": 0, 340 | "_rotationY": 0, 341 | "_quat": { 342 | "__type__": "cc.Quat", 343 | "x": 0, 344 | "y": 0, 345 | "z": 0, 346 | "w": 1 347 | }, 348 | "_skewX": 0, 349 | "_skewY": 0, 350 | "_zIndex": 0, 351 | "groupIndex": 0, 352 | "_id": "44UOOWKsFPJZzHLlhNV4MU" 353 | }, 354 | { 355 | "__type__": "cc.Node", 356 | "_name": "bar", 357 | "_objFlags": 0, 358 | "_parent": { 359 | "__id__": 6 360 | }, 361 | "_children": [], 362 | "_active": true, 363 | "_level": 3, 364 | "_components": [ 365 | { 366 | "__id__": 8 367 | } 368 | ], 369 | "_prefab": { 370 | "__id__": 9 371 | }, 372 | "_opacity": 255, 373 | "_color": { 374 | "__type__": "cc.Color", 375 | "r": 255, 376 | "g": 255, 377 | "b": 255, 378 | "a": 255 379 | }, 380 | "_contentSize": { 381 | "__type__": "cc.Size", 382 | "width": 96, 383 | "height": 100 384 | }, 385 | "_anchorPoint": { 386 | "__type__": "cc.Vec2", 387 | "x": 0.5, 388 | "y": 0.5 389 | }, 390 | "_position": { 391 | "__type__": "cc.Vec3", 392 | "x": 0, 393 | "y": 0, 394 | "z": 0 395 | }, 396 | "_scale": { 397 | "__type__": "cc.Vec3", 398 | "x": 1, 399 | "y": 1, 400 | "z": 1 401 | }, 402 | "_rotationX": 0, 403 | "_rotationY": 0, 404 | "_quat": { 405 | "__type__": "cc.Quat", 406 | "x": 0, 407 | "y": 0, 408 | "z": 0, 409 | "w": 1 410 | }, 411 | "_skewX": 0, 412 | "_skewY": 0, 413 | "_zIndex": 0, 414 | "groupIndex": 0, 415 | "_id": "5fkVpIUdVHSq7coL/HTVxm" 416 | }, 417 | { 418 | "__type__": "cc.Sprite", 419 | "_name": "", 420 | "_objFlags": 0, 421 | "node": { 422 | "__id__": 7 423 | }, 424 | "_enabled": true, 425 | "_srcBlendFactor": 770, 426 | "_dstBlendFactor": 771, 427 | "_spriteFrame": { 428 | "__uuid__": "94dcb3b8-3261-4606-86fc-9401c79d9b85" 429 | }, 430 | "_type": 0, 431 | "_sizeMode": 2, 432 | "_fillType": 0, 433 | "_fillCenter": { 434 | "__type__": "cc.Vec2", 435 | "x": 0, 436 | "y": 0 437 | }, 438 | "_fillStart": 0, 439 | "_fillRange": 0, 440 | "_isTrimmedMode": true, 441 | "_state": 0, 442 | "_atlas": null, 443 | "_id": "08Y7iDWHdK6JHEG/UJh9PP" 444 | }, 445 | { 446 | "__type__": "cc.PrefabInfo", 447 | "root": { 448 | "__id__": 5 449 | }, 450 | "asset": { 451 | "__uuid__": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64" 452 | }, 453 | "fileId": "5fkVpIUdVHSq7coL/HTVxm", 454 | "sync": false 455 | }, 456 | { 457 | "__type__": "cc.Sprite", 458 | "_name": "", 459 | "_objFlags": 0, 460 | "node": { 461 | "__id__": 6 462 | }, 463 | "_enabled": true, 464 | "_srcBlendFactor": 770, 465 | "_dstBlendFactor": 771, 466 | "_spriteFrame": { 467 | "__uuid__": "bbcbdf54-2a7c-4ee2-8744-95e26cc7196e" 468 | }, 469 | "_type": 0, 470 | "_sizeMode": 2, 471 | "_fillType": 0, 472 | "_fillCenter": { 473 | "__type__": "cc.Vec2", 474 | "x": 0, 475 | "y": 0 476 | }, 477 | "_fillStart": 0, 478 | "_fillRange": 0, 479 | "_isTrimmedMode": true, 480 | "_state": 0, 481 | "_atlas": null, 482 | "_id": "7btV0LyElCFLRbJUGZevQv" 483 | }, 484 | { 485 | "__type__": "cc.PrefabInfo", 486 | "root": { 487 | "__id__": 5 488 | }, 489 | "asset": { 490 | "__uuid__": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64" 491 | }, 492 | "fileId": "44UOOWKsFPJZzHLlhNV4MU", 493 | "sync": false 494 | }, 495 | { 496 | "__type__": "cc.Sprite", 497 | "_name": "", 498 | "_objFlags": 0, 499 | "node": { 500 | "__id__": 5 501 | }, 502 | "_enabled": true, 503 | "_srcBlendFactor": 770, 504 | "_dstBlendFactor": 771, 505 | "_spriteFrame": { 506 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 507 | }, 508 | "_type": 0, 509 | "_sizeMode": 0, 510 | "_fillType": 0, 511 | "_fillCenter": { 512 | "__type__": "cc.Vec2", 513 | "x": 0, 514 | "y": 0 515 | }, 516 | "_fillStart": 0, 517 | "_fillRange": 0, 518 | "_isTrimmedMode": true, 519 | "_state": 0, 520 | "_atlas": null, 521 | "_id": "fc3BWwgDlEkaaetzR4Aofj" 522 | }, 523 | { 524 | "__type__": "a962eBT4ohFNbE++6Onpd97", 525 | "_name": "", 526 | "_objFlags": 0, 527 | "node": { 528 | "__id__": 5 529 | }, 530 | "_enabled": true, 531 | "interactable": true, 532 | "fixed": true, 533 | "background": { 534 | "__id__": 6 535 | }, 536 | "bar": { 537 | "__id__": 7 538 | }, 539 | "moveEvents": [ 540 | { 541 | "__id__": 14 542 | } 543 | ], 544 | "_id": "67SFqG9npK4JZAF3vpwj0f" 545 | }, 546 | { 547 | "__type__": "cc.ClickEvent", 548 | "target": { 549 | "__id__": 2 550 | }, 551 | "component": "TestScene", 552 | "handler": "handleMove", 553 | "customEventData": "" 554 | }, 555 | { 556 | "__type__": "cc.PrefabInfo", 557 | "root": { 558 | "__id__": 5 559 | }, 560 | "asset": { 561 | "__uuid__": "dd533e0c-caf7-4e7f-8d54-5e402cde1d64" 562 | }, 563 | "fileId": "92Mi75o4dIJbR3Ti0VtzYu", 564 | "sync": false 565 | }, 566 | { 567 | "__type__": "cc.Node", 568 | "_name": "player", 569 | "_objFlags": 0, 570 | "_parent": { 571 | "__id__": 2 572 | }, 573 | "_children": [], 574 | "_active": true, 575 | "_level": 1, 576 | "_components": [ 577 | { 578 | "__id__": 17 579 | } 580 | ], 581 | "_prefab": null, 582 | "_opacity": 255, 583 | "_color": { 584 | "__type__": "cc.Color", 585 | "r": 255, 586 | "g": 0, 587 | "b": 0, 588 | "a": 255 589 | }, 590 | "_contentSize": { 591 | "__type__": "cc.Size", 592 | "width": 100, 593 | "height": 100 594 | }, 595 | "_anchorPoint": { 596 | "__type__": "cc.Vec2", 597 | "x": 0.5, 598 | "y": 0.5 599 | }, 600 | "_position": { 601 | "__type__": "cc.Vec3", 602 | "x": 308, 603 | "y": -8, 604 | "z": 0 605 | }, 606 | "_scale": { 607 | "__type__": "cc.Vec3", 608 | "x": 1, 609 | "y": 1, 610 | "z": 1 611 | }, 612 | "_rotationX": 0, 613 | "_rotationY": 0, 614 | "_quat": { 615 | "__type__": "cc.Quat", 616 | "x": 0, 617 | "y": 0, 618 | "z": 0, 619 | "w": 1 620 | }, 621 | "_skewX": 0, 622 | "_skewY": 0, 623 | "_zIndex": 0, 624 | "groupIndex": 0, 625 | "_id": "3fvg7ay5BCAKomfS4NOg1W" 626 | }, 627 | { 628 | "__type__": "cc.Sprite", 629 | "_name": "", 630 | "_objFlags": 0, 631 | "node": { 632 | "__id__": 16 633 | }, 634 | "_enabled": true, 635 | "_srcBlendFactor": 770, 636 | "_dstBlendFactor": 771, 637 | "_spriteFrame": { 638 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 639 | }, 640 | "_type": 0, 641 | "_sizeMode": 0, 642 | "_fillType": 0, 643 | "_fillCenter": { 644 | "__type__": "cc.Vec2", 645 | "x": 0, 646 | "y": 0 647 | }, 648 | "_fillStart": 0, 649 | "_fillRange": 0, 650 | "_isTrimmedMode": true, 651 | "_state": 0, 652 | "_atlas": null, 653 | "_id": "f1p2msfjRO9ZNOIr9aSa6C" 654 | }, 655 | { 656 | "__type__": "cc.Canvas", 657 | "_name": "", 658 | "_objFlags": 0, 659 | "node": { 660 | "__id__": 2 661 | }, 662 | "_enabled": true, 663 | "_designResolution": { 664 | "__type__": "cc.Size", 665 | "width": 1280, 666 | "height": 720 667 | }, 668 | "_fitWidth": false, 669 | "_fitHeight": true, 670 | "_id": "685eagD0lFCpVFOZeZejdu" 671 | }, 672 | { 673 | "__type__": "66463qKwiNMD68H53mhcE1f", 674 | "_name": "", 675 | "_objFlags": 0, 676 | "node": { 677 | "__id__": 2 678 | }, 679 | "_enabled": true, 680 | "playerNode": { 681 | "__id__": 16 682 | }, 683 | "speed": 300, 684 | "_id": "7akcGQJ1BG3J9Pyrgt21I9" 685 | } 686 | ] -------------------------------------------------------------------------------- /assets/res/test.fire.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.0", 3 | "uuid": "ca3a401b-c4c3-4b35-addf-399f4198c930", 4 | "asyncLoadAssets": false, 5 | "autoReleaseAssets": false, 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /assets/src.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "478f96e5-1b04-4956-835b-0004d90750b5", 4 | "isSubpackage": false, 5 | "subpackageName": "", 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /assets/src/TestScene.ts: -------------------------------------------------------------------------------- 1 | import { JoystickEvent, Joystick } from "../components/joystick/Joystick"; 2 | 3 | const { ccclass, property } = cc._decorator; 4 | 5 | @ccclass 6 | export class TestScene extends cc.Component { 7 | 8 | @property(cc.Node) 9 | private playerNode: cc.Node = null; 10 | @property(cc.Integer) 11 | private speed: number = 300; 12 | 13 | private moveDirVec: cc.Vec2 = cc.v2(); 14 | 15 | handleMove(event: JoystickEvent) { 16 | this.moveDirVec = Joystick.GetDirVecByDir(event.newDir); 17 | } 18 | 19 | update(dt: number) { 20 | let distance = this.speed * dt; 21 | let moveVec = this.moveDirVec.mul(distance); 22 | this.playerNode.position = this.playerNode.position.add(moveVec); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /assets/src/TestScene.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.5", 3 | "uuid": "66463a8a-c223-4c0f-af07-e779a1704d5f", 4 | "isPlugin": false, 5 | "loadPluginInWeb": true, 6 | "loadPluginInNative": true, 7 | "loadPluginInEditor": false, 8 | "subMetas": {} 9 | } -------------------------------------------------------------------------------- /joystick.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potato47/joystick/fa0102cac485456dc785b63abebc8323ceac348c/joystick.gif -------------------------------------------------------------------------------- /joystick2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potato47/joystick/fa0102cac485456dc785b63abebc8323ceac348c/joystick2.png -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "experimentalDecorators": true 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | ".vscode", 10 | "library", 11 | "local", 12 | "settings", 13 | "temp" 14 | ] 15 | } -------------------------------------------------------------------------------- /nextui-joystick.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potato47/joystick/fa0102cac485456dc785b63abebc8323ceac348c/nextui-joystick.zip -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "engine": "cocos-creator-js", 3 | "packages": "packages" 4 | } -------------------------------------------------------------------------------- /settings/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "start-scene": "current", 3 | "group-list": [ 4 | "default" 5 | ], 6 | "collision-matrix": [ 7 | [ 8 | true 9 | ] 10 | ], 11 | "excluded-modules": [], 12 | "design-resolution-width": 960, 13 | "design-resolution-height": 640, 14 | "fit-width": false, 15 | "fit-height": true, 16 | "use-project-simulator-setting": false, 17 | "simulator-orientation": false, 18 | "use-customize-simulator": false, 19 | "simulator-resolution": { 20 | "width": 960, 21 | "height": 640 22 | }, 23 | "cocos-analytics": { 24 | "enable": false, 25 | "appID": "13798", 26 | "appSecret": "959b3ac0037d0f3c2fdce94f8421a9b2" 27 | } 28 | } --------------------------------------------------------------------------------