diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 70f8403be..4b6d5c5e4 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -7,30 +7,36 @@ on:
jobs:
- sync_latest_from_upstream:
- runs-on: ubuntu-latest
- name: Sync latest commits from upstream repo
- steps:
- - name: Checkout target repo
- uses: actions/checkout@v2
- with:
- ref: main
- token: ${{ secrets.GH_TOKEN }}
- persist-credentials: false
- - name: repo-sync-develop
- uses: repo-sync/github-sync@v2
- with:
- source_repo: "https://${{ secrets.GH_TOKEN }}@github.com//YoYoGames/GameMaker-Manual.git"
- source_branch: "develop"
- destination_branch: "develop"
- github_token: ${{ secrets.GH_TOKEN }}
- sync_tags: "true"
- - name: repo-sync-lts-2022-r1
- uses: repo-sync/github-sync@v2
- with:
- source_repo: "https://${{ secrets.GH_TOKEN }}@github.com//YoYoGames/GameMaker-Manual.git"
- source_branch: "lts-2022-r1"
- destination_branch: "lts-2022-r1"
- github_token: ${{ secrets.GH_TOKEN }}
- sync_tags: "true"
-
+ sync_latest_from_upstream:
+ runs-on: ubuntu-latest
+ name: Sync latest commits from upstream repo
+ steps:
+ - name: Checkout target repo
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ token: ${{ secrets.GH_TOKEN }}
+ persist-credentials: false
+ - name: Sync upstream changes
+ id: sync
+ uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
+ with:
+ target_sync_branch: develop
+ # REQUIRED 'target_repo_token' exactly like this!
+ target_repo_token: ${{ secrets.GH_TOKEN }}
+ upstream_sync_branch: develop
+ upstream_sync_repo: YoYoGames/GameMaker-Manual
+ upstream_repo_access_token: ${{ secrets.GH_TOKEN }}
+ git_config_user: ksuchitra532
+ git_config_email: null
+ git_config_pull_rebase: true
+ - name: Sync upstream changes
+ id: sync-lts
+ uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
+ with:
+ target_sync_branch: main-lts
+ # REQUIRED 'target_repo_token' exactly like this!
+ target_repo_token: ${{ secrets.GH_TOKEN }}
+ upstream_sync_branch: main-lts
+ upstream_sync_repo: YoYoGames/GameMaker-Manual
+ upstream_repo_access_token: ${{ secrets.GH_TOKEN }}
diff --git a/Manual/GMS2_Manual.rhpj b/Manual/GMS2_Manual.rhpj
index f8bba9996..b4816cf25 100644
--- a/Manual/GMS2_Manual.rhpj
+++ b/Manual/GMS2_Manual.rhpj
@@ -1 +1,52 @@
-
Windows Key Binding | macOS Key Binding | Scope | Description | |
---|---|---|---|---|
"+winKeyCombo+" | \n" - - # MacOS key combination - macKeyCombo = replaceMacChars(row[2]) - tableRow += "\t"+macKeyCombo+" | \n" - - # Category/Scope/Section - previousSection = section - tableRow += "\t"+section+" | \n" - - # Description - if description: - tableRow += "\t"+description+" | \n" - else: - tableRow += "\t"+name+" *** | \n" - - tableRow += "
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
F3 | -F3 | -AIAssistant | -- |
SHIFT+F3 | -SHIFT+F3 | -AIAssistant | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
BackSpace | -Delete | -Anim Curve Editor | -- |
Escape | -Escape | -Anim Curve Editor | -- |
CTRL+W | -CTRL+W | -Anim Curve Editor | -- |
CTRL+A | -CMD+A | -Anim Curve Editor | -- |
CTRL+R | -CMD+R | -Anim Curve Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+Right Bracket | -CTRL+Right Bracket | -Asset Browser | -- |
CTRL+Left Bracket | -CTRL+Left Bracket | -Asset Browser | -- |
CTRL+SHIFT+Right Bracket | -CTRL+SHIFT+Right Bracket | -Asset Browser | -- |
CTRL+SHIFT+Left Bracket | -CTRL+SHIFT+Left Bracket | -Asset Browser | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+Insert | -CTRL+Insert | -Errors | -- |
CTRL+SHIFT+A | -CTRL+SHIFT+A | -Errors | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
SHIFT+F11 | -SHIFT+F11 | -Feather | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+A | -CMD+A | -Font Editor | -- |
CTRL+D | -CMD+D | -Font Editor | -- |
CTRL+SHIFT+O | -CMD+SHIFT+O | -Font Editor | -- |
CTRL+R | -CMD+R | -Font Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
Tab | -Tab, | -Global | -- |
SHIFT+Tab | -SHIFT+Tab, | -Global | -- |
Enter | -Enter | -Global | -- |
CTRL+Z | -CMD+Z | -Global | -- |
CTRL+Y | -CMD+Y | -Global | -- |
ALT+F4 | -CMD+Q | -Global | -- |
CTRL+SHIFT+S | -CMD+SHIFT+S | -Global | -- |
CTRL+E | -CMD+E | -Global | -- |
SHIFT+F12 | -SHIFT+F12 | -Global | -- |
CTRL+W | -CMD+W | -Global | -- |
CTRL+Enter | -CMD+Enter | -Global | -- |
CTRL+Equals | -CMD+Equals | -Global | -- |
CTRL+Minus | -CMD+Minus | -Global | -- |
CTRL+ALT+Enter | -CMD+ALT+Enter | -Global | -- |
CTRL+ALT+Up | -CMD+ALT+Up | -Global | -- |
CTRL+ALT+Down | -CMD+ALT+Down | -Global | -- |
CTRL+ALT+Left | -CMD+ALT+Left | -Global | -- |
CTRL+ALT+Right | -CMD+ALT+Right | -Global | -- |
CTRL+ALT+Up+Left | -CMD+ALT+Up+Left | -Global | -- |
CTRL+ALT+Down+Left | -CMD+ALT+Down+Left | -Global | -- |
CTRL+ALT+Up+Right | -CMD+ALT+Up+Right | -Global | -- |
CTRL+ALT+Down+Right | -CMD+ALT+Down+Right | -Global | -- |
F2 | -F2 | -Global | -- |
Escape | -Escape | -Global | -- |
CTRL+D | -CMD+D | -Global | -- |
CTRL+X | -CMD+X | -Global | -- |
CTRL+C | -CMD+C | -Global | -- |
CTRL+V | -CMD+V | -Global | -- |
CTRL+A | -CMD+A | -Global | -- |
CTRL+K | -CMD+K | -Global | -- |
CTRL+SHIFT+K | -CMD+SHIFT+K | -Global | -- |
CTRL+PageUp | -CMD+PageUp | -Global | -- |
CTRL+PageDown | -CMD+PageDown | -Global | -- |
F7 | -F7 | -Global | -- |
F8 | -F8 | -Global | -- |
Delete | -Delete | -Global | -- |
F5 | -F5 | -Global | -- |
F11 | -CMD+SHIFT+I | -Global | -- |
F10 | -CMD+SHIFT+O | -Global | -- |
SHIFT+F11 | -CMD+SHIFT+U | -Global | -- |
CTRL+SHIFT+P | -CMD+SHIFT+P | -Global | -- |
CTRL+T | -CMD+T | -Global | -- |
CTRL+Tab | -CTRL+Tab, | -Global | -- |
F5 | -F5 | -Global | -- |
F6 | -F6 | -Global | -- |
CTRL+F7 | -CMD+F7 | -Global | -- |
CTRL+F8 | -CMD+F8 | -Global | -- |
- | CMD+SHIFT+V | -Global | -- |
- | CMD+SHIFT+D | -Global | -- |
- | CMD+SHIFT+M | -Global | -- |
CTRL+SHIFT+F | -CMD+SHIFT+F | -Global | -- |
CTRL+F | -CMD+F | -Global | -- |
CTRL+H | -CMD+R | -Global | -- |
CTRL+SHIFT+I | -CTRL+SHIFT+I | -Global | -- |
CTRL+SHIFT+0 | -CMD+CTRL+0 | -Global | -- |
CTRL+0 | -CMD+0 | -Global | -- |
CTRL+SHIFT+1 | -CMD+CTRL+1 | -Global | -- |
CTRL+1 | -CMD+1 | -Global | -- |
CTRL+SHIFT+2 | -CMD+CTRL+2 | -Global | -- |
CTRL+2 | -CMD+2 | -Global | -- |
CTRL+SHIFT+3 | -CMD+CTRL+3 | -Global | -- |
CTRL+3 | -CMD+3 | -Global | -- |
CTRL+SHIFT+4 | -CMD+CTRL+4 | -Global | -- |
CTRL+4 | -CMD+4 | -Global | -- |
CTRL+SHIFT+5 | -CMD+CTRL+5 | -Global | -- |
CTRL+5 | -CMD+5 | -Global | -- |
CTRL+SHIFT+6 | -CMD+CTRL+6 | -Global | -- |
CTRL+6 | -CMD+6 | -Global | -- |
CTRL+SHIFT+7 | -CMD+CTRL+7 | -Global | -- |
CTRL+7 | -CMD+7 | -Global | -- |
CTRL+SHIFT+8 | -CMD+CTRL+8 | -Global | -- |
CTRL+8 | -CMD+8 | -Global | -- |
CTRL+SHIFT+9 | -CMD+CTRL+9 | -Global | -- |
CTRL+9 | -CMD+9 | -Global | -- |
SHIFT+O | -SHIFT+O | -Global | -- |
CTRL+SHIFT+B | -CTRL+SHIFT+B | -Global | -- |
CTRL+SHIFT+A | -CTRL+SHIFT+A | -Global | -- |
F3 | -F3 | -Global | -- |
SHIFT+F3 | -SHIFT+F3 | -Global | -- |
CTRL+SHIFT+R | -CTRL+SHIFT+R | -Global | -- |
CTRL+P | -CMD+P | -Global | -- |
CTRL+R | -CMD+R | -Global | -- |
X | -X | -Global | -- |
Y | -Y | -Global | -- |
CTRL+G | -CMD+G | -Global | -- |
CTRL+Semicolon | -CTRL+Semicolon | -Global | -- |
CTRL+ALT+SHIFT+Semicolon | -CTRL+ALT+SHIFT+Semicolon | -Global | -- |
CTRL+SHIFT+Semicolon | -CTRL+SHIFT+Semicolon | -Global | -- |
Space | -Space | -Global | -- |
G | -G | -Global | -- |
Left | -Left | -Global | -- |
Right | -Right | -Global | -- |
Up | -Up | -Global | -- |
Down | -Down | -Global | -- |
- | CMD+SHIFT+Q | -Global | -- |
CTRL+N | -CMD+N | -Global | -- |
CTRL+O | -CMD+O | -Global | -- |
CTRL+S | -CMD+S | -Global | -- |
ALT+J | -ALT+J | -Global | -- |
ALT+E | -ALT+E | -Global | -- |
ALT+F | -ALT+F | -Global | -- |
ALT+N | -ALT+N | -Global | -- |
ALT+O | -ALT+O | -Global | -- |
ALT+P | -ALT+P | -Global | -- |
ALT+R | -ALT+R | -Global | -- |
ALT+C | -ALT+C | -Global | -- |
ALT+G | -ALT+G | -Global | -- |
ALT+A | -ALT+A | -Global | -- |
ALT+U | -ALT+U | -Global | -- |
ALT+S | -ALT+S | -Global | -- |
ALT+B | -ALT+B | -Global | -- |
ALT+T | -ALT+T | -Global | -- |
ALT+K | -ALT+K | -Global | -- |
CTRL+SHIFT+E | -CMD+SHIFT+E | -Global | -- |
CTRL+Space | -CMD+Space | -Global | -- |
CTRL+SHIFT+N | -CMD+SHIFT+N | -Global | -- |
CTRL+SHIFT+E | -CMD+SHIFT+E | -Global | -- |
CTRL+SHIFT+S | -CMD+SHIFT+S | -Global | -- |
CTRL+F | -CMD+F | -Global | -- |
CTRL+A | -CMD+A | -Global | -- |
CTRL+C | -CMD+C | -Global | -- |
PageDown | -PageDown | -Global | -- |
PageUp | -PageUp | -Global | -- |
F1 | -F1 | -Global | -- |
F12 | -F12 | -Global | -- |
CTRL | -CMD | -Global | -- |
Space | -Space | -Global | -- |
CTRL | -CMD | -Global | -- |
SHIFT | -SHIFT | -Global | -- |
ALT | -ALT | -Global | -- |
CTRL | -CMD | -Global | -- |
SHIFT | -SHIFT | -Global | -- |
CTRL+Q | -CTRL+Q | -Global | -- |
ALT+K | -ALT+K | -Global | -- |
ALT+I | -ALT+I | -Global | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
Equals | -Equals | -Image Editor | -- |
KeypadPlus | -KeypadPlus | -Image Editor | -- |
Minus | -Minus | -Image Editor | -- |
KeypadMinus | -KeypadMinus | -Image Editor | -- |
Period | -Period | -Image Editor | -- |
B | -B | -Image Editor | -- |
3 | -3 | -Image Editor | -- |
Enter | -Enter | -Image Editor | -- |
ALT+V | -ALT+V | -Image Editor | -- |
ALT+H | -ALT+H | -Image Editor | -- |
ALT+C | -ALT+C | -Image Editor | -- |
ALT+F | -ALT+F | -Image Editor | -- |
2 | -2 | -Image Editor | -- |
1 | -1 | -Image Editor | -- |
SHIFT+Delete | -SHIFT+Delete | -Image Editor | -- |
CTRL+Insert | -CTRL+Insert | -Image Editor | -- |
SHIFT+Insert | -SHIFT+Insert | -Image Editor | -- |
CTRL+B | -CTRL+B | -Image Editor | -- |
CTRL+I | -CTRL+I | -Image Editor | -- |
SHIFT+A | -SHIFT+A | -Image Editor | -- |
Insert | -Insert | -Image Editor | -- |
BackSpace | -Delete | -Image Editor | -- |
CTRL+SHIFT+A | -CMD+SHIFT+A | -Image Editor | -- |
CTRL+I | -CMD+I | -Image Editor | -- |
CTRL+I | -CMD+I | -Image Editor | -- |
CTRL+SHIFT+A | -CMD+SHIFT+A | -Image Editor | -- |
ALT+C | -ALT+C | -Image Editor | -- |
ALT+F | -ALT+F | -Image Editor | -- |
D | -D | -Image Editor | -- |
E | -E | -Image Editor | -- |
F | -F | -Image Editor | -- |
H | -H | -Image Editor | -- |
V | -V | -Image Editor | -- |
L | -L | -Image Editor | -- |
O | -O | -Image Editor | -- |
R | -R | -Image Editor | -- |
SHIFT+R | -SHIFT+R | -Image Editor | -- |
C | -C | -Image Editor | -- |
SHIFT+C | -SHIFT+C | -Image Editor | -- |
S | -S | -Image Editor | -- |
Q | -Q | -Image Editor | -- |
W | -W | -Image Editor | -- |
P | -P | -Image Editor | -- |
SHIFT+P | -SHIFT+P | -Image Editor | -- |
A | -A | -Image Editor | -- |
U | -U | -Image Editor | -- |
Z | -Z | -Image Editor | -- |
M | -M | -Image Editor | -- |
T | -T | -Image Editor | -- |
CTRL | -CMD | -Image Editor | -- |
SHIFT+Z | -SHIFT+Z | -Image Editor | -- |
CTRL | -CMD | -Image Editor | -- |
ALT | -ALT | -Image Editor | -- |
SHIFT | -SHIFT | -Image Editor | -- |
ALT | -ALT | -Image Editor | -- |
SHIFT | -SHIFT | -Image Editor | -- |
ALT | -ALT | -Image Editor | -- |
ALT | -ALT | -Image Editor | -- |
CTRL | -CTRL | -Image Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+SHIFT+F | -CMD+SHIFT+F | -Context Menu | -- |
F1 | -F1 | -Context Menu | -- |
1 | -1 | -Context Menu | -- |
2 | -2 | -Context Menu | -- |
3 | -3 | -Context Menu | -- |
4 | -4 | -Context Menu | -- |
5 | -5 | -Context Menu | -- |
6 | -6 | -Context Menu | -- |
7 | -7 | -Context Menu | -- |
8 | -8 | -Context Menu | -- |
9 | -9 | -Context Menu | -- |
0 | -0 | -Context Menu | -- |
C | -C | -Context Menu | -- |
M | -M | -Context Menu | -- |
R | -R | -Context Menu | -- |
Del | -Del | -Context Menu | -- |
F9 | -F9 | -Context Menu | -- |
CTRL+P | -CTRL+P | -Context Menu | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
SHIFT+Insert | -SHIFT+Insert | -Object Editor | -- |
CTRL+Insert | -CTRL+Insert | -Object Editor | -- |
SHIFT+Delete | -SHIFT+Delete | -Object Editor | -- |
CTRL+SHIFT+M | -CMD+SHIFT+M | -Object Editor | -- |
CTRL+K | -CMD+K | -Object Editor | -- |
CTRL+F | -CMD+F | -Object Editor | -- |
CTRL+G | -CMD+G | -Object Editor | -- |
CTRL+H | -CMD+H | -Object Editor | -- |
CTRL+J | -CMD+J | -Object Editor | -- |
CTRL+A | -CMD+A | -Object Editor | -- |
CTRL+P | -CMD+P | -Object Editor | -- |
CTRL+SHIFT+O | -CMD+SHIFT+O | -Object Editor | -- |
CTRL+L | -CMD+L | -Object Editor | -- |
CTRL+B | -CMD+B | -Object Editor | -- |
CTRL+SHIFT+Y | -CMD+Y | -Object Editor | -- |
CTRL+U | -CMD+U | -Object Editor | -- |
CTRL+ALT+T | -CMD+ALT+T | -Object Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+SHIFT+O | -CMD+SHIFT+O | -Path Editor | -- |
Left | -Left | -Path Editor | -- |
Right | -Right | -Path Editor | -- |
Up | -Up | -Path Editor | -- |
Down | -Down | -Path Editor | -- |
R | -R | -Path Editor | -- |
T | -T | -Path Editor | -- |
S | -S | -Path Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+ALT+I | -CMD+ALT+I | -Room Editor | -- |
CTRL+ALT+L | -CMD+ALT+L | -Room Editor | -- |
SHIFT+Delete | -SHIFT+Delete | -Room Editor | -- |
CTRL+Insert | -CTRL+Insert | -Room Editor | -- |
SHIFT+Insert | -SHIFT+Insert | -Room Editor | -- |
SHIFT+X | -SHIFT+X | -Room Editor | -- |
X | -X | -Room Editor | -- |
SHIFT+Y | -SHIFT+Y | -Room Editor | -- |
Y | -Y | -Room Editor | -- |
CTRL+ALT+G | -CMD+ALT+G | -Room Editor | -- |
CTRL+B | -CMD+B | -Room Editor | -- |
CTRL+ALT+T | -CMD+ALT+T | -Room Editor | -- |
CTRL+P | -CMD+P | -Room Editor | -- |
CTRL+A | -CMD+A | -Room Editor | -- |
CTRL+F | -CMD+F | -Room Editor | -- |
CTRL | -CTRL | -Room Editor | -- |
ALT | -ALT | -Room Editor | -- |
P | -P | -Room Editor | -- |
A | -A | -Room Editor | -- |
Y | -Y | -Room Editor | -- |
X | -X | -Room Editor | -- |
E | -E | -Room Editor | -- |
F | -F | -Room Editor | -- |
I | -I | -Room Editor | -- |
L | -L | -Room Editor | -- |
D | -D | -Room Editor | -- |
R | -R | -Room Editor | -- |
Z | -Z | -Room Editor | -- |
S | -S | -Room Editor | -- |
CTRL+ALT+S | -CTRL+ALT+S | -Room Editor | -- |
CTRL+E | -CTRL+E | -Room Editor | -- |
Equals | -Equals | -Room Editor | -- |
Minus | -Minus | -Room Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
F7 | -F7 | -Sequence Editor | -- |
F8 | -F8 | -Sequence Editor | -- |
F9 | -F9 | -Sequence Editor | -- |
F10 | -F10 | -Sequence Editor | -- |
BackSpace | -Delete | -Sequence Editor | -- |
Q | -Q | -Sequence Editor | -- |
CTRL+SHIFT+Home | -CTRL+SHIFT+Home | -Sequence Editor | -- |
CTRL+Home | -CTRL+Home | -Sequence Editor | -- |
CTRL+ALT+P | -CTRL+ALT+P | -Sequence Editor | -- |
ALT+SHIFT+Left | -ALT+SHIFT+Left | -Sequence Editor | -- |
ALT+SHIFT+Right | -ALT+SHIFT+Right | -Sequence Editor | -- |
ALT+Left | -ALT+Left | -Sequence Editor | -- |
ALT+Right | -ALT+Right | -Sequence Editor | -- |
CTRL+SHIFT+Left | -CTRL+SHIFT+Left | -Sequence Editor | -- |
CTRL+SHIFT+Right | -CTRL+SHIFT+Right | -Sequence Editor | -- |
CTRL+Left | -CTRL+Left | -Sequence Editor | -- |
CTRL+Right | -CTRL+Right | -Sequence Editor | -- |
SHIFT+Up | -SHIFT+Up | -Sequence Editor | -- |
SHIFT+Down | -SHIFT+Down | -Sequence Editor | -- |
SHIFT+Left | -SHIFT+Left | -Sequence Editor | -- |
SHIFT+Right | -SHIFT+Right | -Sequence Editor | -- |
Up | -Up | -Sequence Editor | -- |
Down | -Down | -Sequence Editor | -- |
Left | -Left | -Sequence Editor | -- |
Right | -Right | -Sequence Editor | -- |
Left Bracket | -Left Bracket | -Sequence Editor | -- |
Right Bracket | -Right Bracket | -Sequence Editor | -- |
CTRL+ALT+D | -CTRL+ALT+D | -Sequence Editor | -- |
SHIFT+Right Bracket | -SHIFT+Right Bracket | -Sequence Editor | -- |
SHIFT+Left Bracket | -SHIFT+Left Bracket | -Sequence Editor | -- |
N | -N | -Sequence Editor | -- |
M | -M | -Sequence Editor | -- |
SHIFT+N | -SHIFT+N | -Sequence Editor | -- |
SHIFT+M | -SHIFT+M | -Sequence Editor | -- |
Home | -Home | -Sequence Editor | -- |
End | -End | -Sequence Editor | -- |
SHIFT+Home | -SHIFT+Home | -Sequence Editor | -- |
SHIFT+End | -SHIFT+End | -Sequence Editor | -- |
U | -U | -Sequence Editor | -- |
CTRL+U | -CTRL+U | -Sequence Editor | -- |
ALT+Up | -ALT+Up | -Sequence Editor | -- |
ALT+Down | -ALT+Down | -Sequence Editor | -- |
CTRL+ALT+Up | -CTRL+ALT+Up | -Sequence Editor | -- |
CTRL+ALT+Down | -CTRL+ALT+Down | -Sequence Editor | -- |
CTRL+M | -CTRL+M | -Sequence Editor | -- |
ALT+G | -ALT+G | -Sequence Editor | -- |
CTRL+8 | -CTRL+8 | -Sequence Editor | -- |
CTRL+9 | -CTRL+9 | -Sequence Editor | -- |
SHIFT+8 | -SHIFT+8 | -Sequence Editor | -- |
SHIFT+9 | -SHIFT+9 | -Sequence Editor | -- |
T | -T | -Sequence Editor | -- |
S | -S | -Sequence Editor | -- |
R | -R | -Sequence Editor | -- |
Y | -Y | -Sequence Editor | -- |
CTRL+R | -CTRL+R | -Sequence Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+SHIFT+O | -CMD+SHIFT+O | -Sound Editor | -- |
CTRL+SHIFT+M | -CMD+SHIFT+M | -Sound Editor | -- |
M | -M | -Sound Editor | -- |
Space | -Space | -Sound Editor | -- |
L | -L | -Sound Editor | -- |
R | -R | -Sound Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
M | -M | -Sound Mixer | -- |
Space | -Space | -Sound Mixer | -- |
L | -L | -Sound Mixer | -- |
R | -R | -Sound Mixer | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+8 | -CTRL+8 | -Sprite Editor | -- |
SHIFT+A | -SHIFT+A | -Sprite Editor | -- |
Insert | -Insert | -Sprite Editor | -- |
CTRL+Insert | -CTRL+Insert | -Sprite Editor | -- |
SHIFT+Insert | -SHIFT+Insert | -Sprite Editor | -- |
SHIFT+Delete | -SHIFT+Delete | -Sprite Editor | -- |
CTRL+I | -CMD+I | -Sprite Editor | -- |
CTRL+R | -CMD+R | -Sprite Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+Insert | -CTRL+Insert | -Errors | -- |
CTRL+SHIFT+A | -CTRL+SHIFT+A | -Errors | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
Left | -Left | -Text Editor | -- |
Right | -Right | -Text Editor | -- |
Up | -Up | -Text Editor | -- |
Down | -Down | -Text Editor | -- |
SHIFT+Left | -SHIFT+Left | -Text Editor | -- |
SHIFT+Right | -SHIFT+Right | -Text Editor | -- |
SHIFT+Up | -SHIFT+Up | -Text Editor | -- |
SHIFT+Down | -SHIFT+Down | -Text Editor | -- |
ALT+SHIFT+Up | -ALT+SHIFT+Up | -Text Editor | -- |
ALT+SHIFT+Down | -ALT+SHIFT+Down | -Text Editor | -- |
PageUp | -PageUp | -Text Editor | -- |
PageDown | -PageDown | -Text Editor | -- |
SHIFT+PageUp | -SHIFT+PageUp | -Text Editor | -- |
SHIFT+PageDown | -SHIFT+PageDown | -Text Editor | -- |
CTRL+Up | -CTRL+PageUp | -Text Editor | -- |
CTRL+Down | -CTRL+PageDown | -Text Editor | -- |
CTRL+SHIFT+Up | -CTRL+SHIFT+PageUp | -Text Editor | -- |
CTRL+SHIFT+Down | -CTRL+SHIFT+PageDown | -Text Editor | -- |
Home | -Home | -Text Editor | -- |
End | -End | -Text Editor | -- |
SHIFT+Home | -SHIFT+Home | -Text Editor | -- |
SHIFT+End | -SHIFT+End | -Text Editor | -- |
ALT+SHIFT+Home | -ALT+SHIFT+Home | -Text Editor | -- |
ALT+SHIFT+End | -ALT+SHIFT+End | -Text Editor | -- |
CTRL+Home | -CTRL+Home | -Text Editor | -- |
CTRL+End | -CTRL+End | -Text Editor | -- |
CTRL+SHIFT+Home | -CTRL+SHIFT+Home | -Text Editor | -- |
CTRL+SHIFT+End | -CTRL+SHIFT+End | -Text Editor | -- |
CTRL+Left | -ALT+Left | -Text Editor | -- |
CTRL+Right | -ALT+Right | -Text Editor | -- |
CTRL+SHIFT+Left | -ALT+SHIFT+Left | -Text Editor | -- |
CTRL+SHIFT+Right | -ALT+SHIFT+Right | -Text Editor | -- |
BackSpace | -Delete | -Text Editor | -- |
Delete | -Delete | -Text Editor | -- |
Enter | -Enter | -Text Editor | -- |
KeypadEnter | -KeypadEnter | -Text Editor | -- |
Tab | -Tab, | -Text Editor | -- |
SHIFT+Tab | -SHIFT+Tab, | -Text Editor | -- |
CTRL+BackSpace | -ALT+Delete | -Text Editor | -- |
CTRL+Delete | -CTRL+Delete | -Text Editor | -- |
- | CMD+Delete | -Text Editor | -- |
- | CTRL+K | -Text Editor | -- |
F4 | -F4 | -Text Editor | -- |
CTRL+M | -CTRL+M | -Text Editor | -- |
CTRL+U | -CTRL+U | -Text Editor | -- |
CTRL+Enter | -CMD+Enter | -Text Editor | -- |
CTRL+ALT+Up | -CMD+ALT+Up | -Text Editor | -- |
CTRL+ALT+Down | -CMD+ALT+Down | -Text Editor | -- |
Insert | -Insert | -Text Editor | -- |
CTRL+Space | -CTRL+Space | -Text Editor | -- |
F6 | -F6 | -Text Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+I | -CTRL+I | -Tileset Editor | -- |
Delete | -Delete | -Tileset Editor | -- |
Insert | -Insert | -Tileset Editor | -- |
Up | -Up | -Tileset Editor | -- |
Down | -Down | -Tileset Editor | -- |
Left | -Left | -Tileset Editor | -- |
Right | -Right | -Tileset Editor | -- |
SHIFT+Up | -SHIFT+Up | -Tileset Editor | -- |
SHIFT+Down | -SHIFT+Down | -Tileset Editor | -- |
SHIFT+Left | -SHIFT+Left | -Tileset Editor | -- |
SHIFT+Right | -SHIFT+Right | -Tileset Editor | -- |
KeypadPlus | -KeypadPlus | -Tileset Editor | -- |
KeypadMinus | -KeypadMinus | -Tileset Editor | -- |
CTRL+SHIFT+O | -CMD+SHIFT+O | -Tileset Editor | -- |
CTRL+B | -CMD+B | -Tileset Editor | -- |
CTRL+ALT+T | -CMD+ALT+T | -Tileset Editor | -- |
CTRL+A | -CMD+A | -Tileset Editor | -- |
CTRL+F | -CMD+F | -Tileset Editor | -- |
CTRL+R | -CMD+R | -Tileset Editor | -- |
D | -D | -Tileset Editor | -- |
E | -E | -Tileset Editor | -- |
F | -F | -Tileset Editor | -- |
L | -L | -Tileset Editor | -- |
R | -R | -Tileset Editor | -- |
S | -S | -Tileset Editor | -- |
A | -A | -Tileset Editor | -- |
Z | -Z | -Tileset Editor | -- |
Del | -Del | -Tileset Editor | -- |
G | -G | -Tileset Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
Insert | -Enter | -Timeline Editor | -- |
SHIFT+Delete | -SHIFT+Delete | -Timeline Editor | -- |
CTRL+Insert | -CTRL+Insert | -Timeline Editor | -- |
SHIFT+Insert | -SHIFT+Insert | -Timeline Editor | -- |
CTRL+SHIFT+E | -CMD+SHIFT+E | -Timeline Editor | -- |
CTRL+SHIFT+M | -CMD+SHIFT+M | -Timeline Editor | -- |
CTRL+U | -CMD+U | -Timeline Editor | -- |
ALT+Enter | -ALT+Enter | -Timeline Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
Insert | -- | Context Menu | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+G | -- | Text Editor | -- |
ALT+SHIFT+Left | -- | Text Editor | -- |
ALT+SHIFT+Right | -- | Text Editor | -- |
Windows Key Binding | macOS Key Binding | Scope | Description |
---|---|---|---|
CTRL+ALT+M | -- | Global | -- |
Keyword Description Goes Here.
-Additional Information Goes Here.
--
keyword_name(arguments);
-Argument | -Type | -Description | -
---|---|---|
argument_name | -<Type_ Variable> | -Argument Description Goes Here | -
-
<Type_ Variable> (Optional explanation)
--
code_example () {
-
- }
Explain The Code Example Here
--
- - - - - \ No newline at end of file diff --git a/Manual/_page_generation/Template_Normal_Page.htm b/Manual/_page_generation/Template_Normal_Page.htm deleted file mode 100644 index ac45a138b..000000000 --- a/Manual/_page_generation/Template_Normal_Page.htm +++ /dev/null @@ -1,40 +0,0 @@ - - - - - -
-
-
-
- - - - - - \ No newline at end of file diff --git a/Manual/_page_generation/Template_Visual_Page.htm b/Manual/_page_generation/Template_Visual_Page.htm deleted file mode 100644 index 820bb10c1..000000000 --- a/Manual/_page_generation/Template_Visual_Page.htm +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -
Description
--
Argument | -Description | -
---|---|
- | - |
-
The above actions
- --
- - - - - \ No newline at end of file diff --git a/Manual/_page_generation/insert_text.bat b/Manual/_page_generation/insert_text.bat deleted file mode 100644 index 322eae9d1..000000000 --- a/Manual/_page_generation/insert_text.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off -set inputfile=%1 -set outputfile=%2 -set texttofind=%3 -set texttoprepend=%~4 - -set inserted=0 ->"%outputfile%" ( - for /f "usebackq delims=" %%a in ("%inputfile%") do ( - if %inserted%==0 if "%%~a"==%texttofind% echo(%texttoprepend% & set inserted=1 - echo(%%a - ) -) \ No newline at end of file diff --git a/Manual/_page_generation/replace_text.bat b/Manual/_page_generation/replace_text.bat deleted file mode 100644 index 4e9b544a0..000000000 --- a/Manual/_page_generation/replace_text.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -REM -- Prepare the Command Processor -- -SETLOCAL ENABLEEXTENSIONS -SETLOCAL DISABLEDELAYEDEXPANSION - -::BatchSubstitude - parses a File line by line and replaces a substring" -::syntax: BatchSubstitude.bat OldStr NewStr File -:: OldStr [in] - string to be replaced -:: NewStr [in] - string to replace with -:: File [in] - file to be parsed -:$changed 20100115 -:$source https://www.dostips.com -if "%~1"=="" findstr "^::" "%~f0"&GOTO:EOF -for /f "tokens=1,* delims=]" %%A in ('"type %3|find /n /v """') do ( - set "line=%%B" - if defined line ( - call set "line=echo.%%line:%~1=%~2%%" - for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X - ) ELSE echo. -) \ No newline at end of file diff --git a/Manual/contents/Additional_Information/Additional_Information.htm b/Manual/contents/Additional_Information/Additional_Information.htm index 7a7b1ba32..281b14cd2 100644 --- a/Manual/contents/Additional_Information/Additional_Information.htm +++ b/Manual/contents/Additional_Information/Additional_Information.htm @@ -3,10 +3,10 @@ -
This section of the manual contain a collection of miscellaneous articles related to programming and the way the GameMaker Language works. The following articles are designed as companion articles to further expand your understanding of how GameMaker works and how to get the most from the different language features available:
+Ta część podręcznika zawiera zbiór różnych artykułów związanych z programowaniem i sposobem działania GameMaker Language. Poniższe artykuły zostały pomyślane jako artykuły towarzyszące, aby jeszcze bardziej poszerzyć wiedzę o tym, jak działa GameMaker i jak w pełni wykorzystać różne dostępne funkcje języka:
-
+
+
+
-
On this page we are going to cover some "best practices" when programming your game, and at the same time explain a little bit about the inner workings of GameMaker. Before continuing, however, it is worth noting two very important points:
+Na tej stronie zamierzamy omówić kilka "najlepszych praktyk" przy programowaniu gry, a jednocześnie wyjaśnić trochę o wewnętrznym działaniu GameMakera. Zanim jednak przejdziemy dalej, warto zwrócić uwagę na dwie bardzo ważne kwestie:
With that said, lets move on and look at some general tips for writing good GML code that you can apply at any time...
- +W związku z tym, przejdźmy dalej i spójrzmy na kilka ogólnych wskazówek dotyczących pisania dobrego kodu GML, które można zastosować w dowolnym momencie...
+When it comes to writing code everyone has a style. The style you program in is the way you place your brackets, how you indent the lines, and how you declare and name variables, etc., and is essential to making your code clear and readable to other people (and to your future self, when you have to come back to this project after a time on something else).
-There are many, many programming styles, and some would argue that theirs is the best one to use, but the truth is that almost any style is fine as long as you are consistent when using it and it is clear and obvious what everything is and does.
-The above image is an example of a function declaration in a script to illustrate the above points. You can see that it uses the JSDoc style comments to clearly explain what it all does, and the coding style is consistent, with 4 space indents, underscores used for local vars, logged output, etc...
-Also note that while the script editor permits you to fold code at each of the open/close brackets, you can use #region and #endregion tags to section off parts of your code and greatly enhance readability, especially when dealing with larger scripts which contain multiple functions. Regions can be commented, too - see the Editing section of this page in the manual):
-When writing code, you should be aware that when compiling your final game, GameMaker strips out comments, removes unnecessary line breaks and whitespace, substitutes in constant/macro/enum values, and generally compresses your code down as part of the process. This means that you can add as much whitespace around your code as required and you don't need to worry about keeping your comments short or only using them sparingly.
-+
Jeśli chodzi o pisanie kodu, każdy ma swój styl. Styl, w którym programujesz, to sposób, w jaki umieszczasz nawiasy, jak wcina się linie, jak deklarujesz i nazywasz zmienne itp. i jest niezbędny, aby twój kod był jasny i czytelny dla innych ludzi (i dla twojego przyszłego ja, kiedy będziesz musiał wrócić do tego projektu po czasie spędzonym nad czymś innym).
+Istnieje wiele, wiele stylów programowania, a niektórzy twierdzą, że ich jest najlepszy do użycia, ale prawda jest taka, że prawie każdy styl jest w porządku, o ile jesteś konsekwentny podczas korzystania z niego i jest jasne i oczywiste , co wszystko jest i robi.
+Powyższy obraz jest przykładem deklaracji funkcji w script, aby zilustrować powyższe punkty. Możesz zobaczyć, że używa komentarzy w stylu JSDoc, aby wyraźnie wyjaśnić, co to wszystko robi, a styl kodowania jest spójny, z 4 spacjami wcięciami, podkreśleniami używanymi do lokalnych vars, logowanym wyjściem, itp.
+Zauważ również, że podczas gdy edytor script pozwala na składanie kodu w każdym z nawiasów otwierających/zamykających, możesz użyć znaczników #region i #endregion, aby wydzielić części kodu i znacznie zwiększyć czytelność, zwłaszcza gdy masz do czynienia z większymi scripts, które zawierają wiele funkcji. Regiony można też komentować - patrz rozdział Edycja na tej stronie w podręczniku):
+Kiedy piszesz kod, powinieneś być świadomy tego, że podczas kompilacji Twojej finalnej gry, GameMaker usuwa komentarze, usuwa niepotrzebne przerwy w liniach i białe przestrzenie, zastępuje wartości stałe/makro/enum i ogólnie kompresuje Twój kod jako część procesu. Oznacza to, że możesz dodać tyle białej przestrzeni wokół swojego kodu, ile potrzebujesz i nie musisz się martwić o to, że komentarze będą krótkie lub że będziesz ich używał oszczędnie.
+
Continuing on from the above point about programming style, one thing that a lot of beginners do is to cram as much into one line of code as possible. For example:
+Kontynuując powyższy punkt dotyczący stylu programowania, jedną z rzeczy, którą robi wielu początkujących, jest upchnięcie jak najwięcej w jednej linii kodu. Na przykład:
draw_sprite(sprite_index, image_index, x + lengthdir_x(100, point_direction(x, y, mouse_x, mouse_y)), y + lengthdir_y(100, point_direction(x, y, mouse_x, mouse_y)));
-While not completely unreadable, it is inefficient (the point_direction() function is called twice, for example) and it is messy and awkward to look at. It would be far better expressed as:
+Chociaż nie jest całkowicie nieczytelny, jest nieefektywny (funkcja point_direction() jest wywoływana dwa razy, na przykład) i jest niechlujny i niewygodny do oglądania. Byłoby to o wiele lepiej wyrażone jako:
var p_dir = point_direction(x, y, mouse_x, mouse_y);
var local_x = x + lengthdir_x(100, p_dir);
var local_y = y + lengthdir_y(100, p_dir);
draw_sprite(sprite_index, image_index, local_x, local_y);
The memory and resources required to create those local variables are negligible, and are far outweighed by the instant benefit you (or anyone else reading the code later) gets from its clarity. The same idea should be applied to functions too, where you should assign sensible names to the input variables, and use clear formatting and local variables where required to make it as readable as possible.
-Local variables are fast to process in-game, so make the most of them, and if an expression appears in a code block or script two or more times, think about creating a local variable for it. When using the YoYo Compiler (YYC) targets, if you reference global or instance variables various times in a function or code block it is particularly beneficial to assign them to a local variable at the start of your code and then reference that local variable, as this will give much better performance.
-+
Pamięć i zasoby wymagane do stworzenia tych zmiennych lokalnych są znikome i są znacznie przewyższone przez natychmiastową korzyść, jaką ty (lub ktokolwiek inny czytający kod później) otrzymuje z jego przejrzystości. Ta sama idea powinna być stosowana również do funkcji, gdzie powinieneś przypisać rozsądne nazwy do zmiennych wejściowych i użyć wyraźnego formatowania i zmiennych lokalnych, gdzie jest to wymagane, aby uczynić go tak czytelnym, jak to możliwe.
+Zmienne lokalne są szybko przetwarzane w grze, więc wykorzystaj je jak najlepiej, a jeśli jakieś wyrażenie pojawia się w bloku kodu lub na stronie script dwa lub więcej razy, pomyśl o stworzeniu dla niego zmiennej lokalnej. Podczas korzystania z celów YoYo Compiler (YYC), jeśli odwołujesz się do global lub zmiennych instancji wiele razy w funkcji lub bloku kodu, szczególnie korzystne jest przypisanie ich do zmiennej lokalnej na początku kodu, a następnie odwołanie się do tej zmiennej lokalnej, ponieważ daje to znacznie lepszą wydajność.
+
Arrays are fast to use and require less memory than data-structures, but they can be optimised further still. When you create an array, memory is allocated to it based on its size, so you should try to initialise an array to its maximum size first, even if you don't plan on filling it until later on. For example, if you know you need an array to hold a maximum of 100 values, you would initialise it to 100 slots straight away, using the array_create() function:
+Tablice są szybkie w użyciu i wymagają mniej pamięci niż struktury danych, ale można je jeszcze bardziej zoptymalizować. Kiedy tworzysz tablicę, pamięć jest przydzielana na podstawie jej rozmiaru, więc powinieneś spróbować zainicjować tablicę do jej maksymalnego rozmiaru, nawet jeśli nie planujesz jej wypełnienia do późniejszego czasu. Na przykład, jeśli wiesz, że potrzebujesz tablicy do przechowywania maksymalnie 100 wartości, zainicjalizowałbyś ją od razu do 100 slotów, używając array_create() funkcja:
array = array_create(100, 0);
-This allocates the memory for it in one "chunk" with all array values being set to the default value of 0 and helps keep things fast, as otherwise every time you add a new value to the array the entire memory has to be re-allocated again.
-NOTE On the HTML5 target assigning arrays like this does not apply and your arrays should be initialised from 0 for this target! You can easily handle this by checking the os_browser variable, for example:
+To przydziela pamięć dla niej w jednym "kawałku" z wszystkimi wartościami tablicy ustawionymi na domyślną wartość 0 i pomaga utrzymać rzeczy szybko, ponieważ w przeciwnym razie za każdym razem, gdy dodajesz nową wartość do tablicy, cała pamięć musi być ponownie przydzielona.
+UWAGA Na celu HTML5 przypisywanie tablic w ten sposób nie ma zastosowania, a twoje tablice powinny być inicjalizowane od 0 dla tego celu! Możesz łatwo sobie z tym poradzić, sprawdzając zmienną os_browser, na przykład:
if (os_browser == browser_not_a_browser)
{
array_create(100, 0);
@@ -60,36 +60,53 @@ Best Practices When Programming
array[i] = 0;
}
}
You can also free up the memory associated with an array by setting the variable used to equal 0. So, to clear the array from the code example above you would simply use:
+Możesz również zwolnić pamięć związaną z tablicą, ustawiając używaną zmienną na równość 0. Tak więc, aby wyczyścić tablicę z powyższego przykładu kodu, po prostu użyłbyś:
array = 0;
-+
Zauważ również, że tablice są przekazywane przez odniesienie, ale będą kopiować całość, gdy nastąpi zmiana (to zachowanie nazywa się copy on write). Tak więc, jeśli przekazujesz tablicę do funkcji, przekazujesz referencję do oryginalnej tablicy, a wszelkie wartości odczytane z niej będą pochodzić z oryginalnego źródła. Jest to miłe i szybkie, ale jeśli musisz zmodyfikować dowolną wartość tablicy, sama tablica jest duplikowana w punkcie zapisu, a wszelkie dokonane zmiany muszą zostać zwrócone z funkcji lub zostaną utracone. Jest to znacznie wolniejsze i zużywa więcej pamięci, więc uważaj, jak używasz tablic w funkcjach.
+Można jednak uniknąć tego zachowania copy on write, używając specjalnego accessora tablicowego @, ponieważ daje to bezpośredni dostęp do tablicy bazowej. Na przykład:
+// Call a function, passing our array
+ my_function(my_array);
// The function looks like this:
+
+ function my_function(_a)
+ {
+ // The array will be copied and the copy modified,
+ // requiring you to use "return _a", later
+ _a[0] = 100;
+
+ // This will modify the ORIGINAL array directly and
+ // does not require it to be returned
+ _a[@ 0] = 100;
+ }
+
In GameMaker data structures have been optimised to be a lot faster than previous GameMaker versions. They still need to be cleaned up (destroyed) when not used to free memory, and they can still be slower than, say, arrays, but the ease of use and the extra functions for dealing with the data they contain can often out-weigh the minimal speed difference, so don't be afraid to use them in your games.
-It should be noted that of all the data structures, DS Maps in particular are lighting fast, both to read from and write to, making them an excellent option for all types of tasks.
-Previously we mentioned accessors for arrays, but they are also available for data structures, which can help clean up your code and make it much easier to read.
-+
W GameMakerze struktury danych zostały zoptymalizowane tak, aby były o wiele szybsze niż w poprzednich wersjach GameMaker. Nadal muszą być czyszczone (niszczone), gdy nie są używane, aby zwolnić pamięć, i nadal mogą być wolniejsze niż, powiedzmy, tablice, ale łatwość użycia i dodatkowe funkcje do radzenia sobie z danymi, które zawierają, często przewyższają minimalną różnicę w prędkości, więc nie bój się używać ich w swoich grach.
+Należy zauważyć, że ze wszystkich struktur danych, DS Maps w szczególności są oświetleniem szybkie, zarówno do odczytu z i zapisu do, co czyni je doskonałą opcją dla wszystkich rodzajów zadań.
+Wcześniej wspomnieliśmy o accessorach dla tablic, ale są one również dostępne dla struktur danych, co może pomóc w oczyszczeniu twojego kodu i uczynić go znacznie łatwiejszym do odczytania.
+
There are multiple ways to deal with collisions in GameMaker, and most of them come with a bit of extra CPU overhead attached. The collision_ and point_ functions, place_ functions, and instance_ functions all rely on bounding box checks with all instances of a given type within the room, and while there is some optimisation built in to the engine to limit these checks, collisions are never the most effecient thing to deal with. If you start to use precise collisions, performance will also get noticably worse, as not only will you be doing bounding box checks, but you will also be doing per-pixel checks, which is very slow indeed.
+Istnieje wiele sposobów radzenia sobie z kolizjami w GameMakerze, a większość z nich wiąże się z dodatkowym obciążeniem procesora. Funkcje collision_ i point_, place_ oraz instance_ polegają na sprawdzaniu pól ograniczających dla wszystkich instancji danego typu w obrębie room i chociaż silnik posiada pewną optymalizację, która ogranicza te sprawdzenia, kolizje nigdy nie są najbardziej wydajną rzeczą. Jeśli zaczniesz używać precyzyjnych kolizji, wydajność również ulegnie zauważalnemu pogorszeniu, ponieważ nie tylko będziesz sprawdzał bounding box, ale również będziesz sprawdzał per-pixel, co jest bardzo powolne.
That is not to say that you shouldn't use these functions, as they can be very handy. However, you should know which ones to use and when, as they all work slightly differently and will have different speeds. Rough rule of thumb is that the place_ functions are faster than the instance_ functions, which are faster than the collision_ and point_ functions, so read the pages in the manual for each of these types of functions and make sure to choose the most appropriate for every situation.
-Alternatively, look into creating a tile-based collision system, which can be created using the tilemap functions or even a custom 2D array or DS grid. These will be very fast and will help boost your game's speed. However, if you are using irregular terrain or walls and objects that don't align to a grid they may not be appropriate. You can find a very simple tutorial on tilemap collisions from the following video link
+Nie oznacza to, że nie powinieneś używać tych funkcji, ponieważ mogą być bardzo przydatne. Powinieneś jednak wiedzieć, których z nich używać i kiedy, ponieważ wszystkie działają nieco inaczej i mają różne prędkości. Z grubsza zasada jest taka, że funkcje place_ są szybsze niż funkcje instance_, które są szybsze niż funkcje collision_ i point_, więc przeczytaj strony w instrukcji dla każdego z tych typów funkcji i upewnij się, że wybierasz najbardziej odpowiednie dla każdej sytuacji.
+Alternatywnie, spójrz na stworzenie systemu kolizji opartego na kafelkach, które można utworzyć za pomocą funkcji tilemap lub nawet niestandardowej tablicy 2D lub siatki DS. Będą one bardzo szybkie i pomogą zwiększyć szybkość gry. Jednakże, jeśli używasz nieregularnego terenu lub ścian i objects, które nie są wyrównane do siatki, mogą one nie być odpowiednie. Bardzo prosty tutorial na temat kolizji z mapami można znaleźć w poniższym linku wideo
-+
Texture Swaps And Vertex Batches
+Zamiana tekstur i partie wierzchołków
If you switch on the debug overlay, you will see that there are two figures in brackets at the top of your screen when testing. The first is the number of texture swaps being done and the second is the number of vertex batches. A number of factors will influence these figures and you will never get them down to (0) (0) as the engine requires one or two of each every step, but you should aim to get these values down as low as possible.
-For texture swaps, the best and most efficient way to do this is to optimise how your sprites and backgrounds are stored on the texture page. This is done from the sprite properties, and you can create texture pages in the Texture Group Editor. If you have a number of images that are only used in the main menu (for example), then put them together on a separate texture page. The same if you have level-specific images, or the player and the enemies, etc. Basically, you want to group them by use so that the swaps are reduced as much as possible. Additionally, to help keep VRAM optimised you can then use the different prefetch and flush functions to load and remove textures from memory as required.
-NOTE As mentioned at the start of this page, if your game runs fine with a decent FPS then don't worry too much about texture swaps... especially when creating projects on the desktop targets. These optimisations are best when used with large games or on low-end mobile devices, and when used incorrectly can they actually negatively impact performance.
-Vertex information is sent in "batches" to the GPU for drawing, and in general the larger the batch the better. So "breaking" the batch should be avoided when drawing, as that will increase the number of vertex batches sent to the GPU. There are a number of things that will break the batch, with the main ones being blend modes, changing the shader, changing a uniform for a shader before drawing something, and drawing using the built-in shapes and primitives.
-So, if you have a number of bullet instances that draw using the bm_add blend mode - for example - you will be creating a new vertex batch for each one, which is definitely a bad thing! Instead, have a controller object in your game that draws all the bullets instead, like this:
+Jeśli switch na nakładka debugowania, zobaczysz, że podczas testowania na górze ekranu znajdują się dwie liczby w nawiasach. Pierwsza to liczba wykonywanych wymian tekstur , a druga to liczba partii wierzchołków. Wiele czynników ma wpływ na te liczby i nigdy nie uda Ci się ich sprowadzić do (0) (0), ponieważ silnik wymaga jednego lub dwóch z każdego kroku, ale powinieneś dążyć do tego, aby te wartości były jak najniższe.
+W przypadku zamiany texture najlepszym i najbardziej efektywnym sposobem jest optymalizacja sposobu przechowywania sprites i tła na stronie texture. Robi się to we właściwościach sprite'a, a strony texture można tworzyć w edytorze grup tekstur. Jeśli masz kilka obrazów, które są używane tylko w menu głównym (na przykład), to umieść je razem na osobnej stronie tekstur. To samo, jeśli masz obrazy specyficzne dla poziomu, lub gracza i wrogów, itp. Zasadniczo, chcesz je pogrupować według użycia, aby zamiany były zredukowane tak bardzo, jak to możliwe. Dodatkowo, aby pomóc w optymalizacji VRAM, możesz następnie użyć różnych funkcji prefetch i flush, aby załadować i usunąć textures z pamięci w razie potrzeby.
+UWAGA Jak wspomniano na początku tej strony, jeśli Twoja gra działa dobrze z przyzwoitym FPS, to nie przejmuj się zbytnio podmianami texture... zwłaszcza przy tworzeniu projektów na cele desktopowe. Te optymalizacje są najlepsze, gdy są używane z dużymi grami lub na urządzeniach mobilnych o niskiej wydajności, a gdy są używane niepoprawnie, mogą faktycznie negatywnie wpłynąć na wydajność.
+Informacje o wierzchołkach są wysyłane w "partiach" do GPU w celu rysowania i generalnie im większa partia, tym lepiej. Należy więc unikać "przerywania" partii podczas rysowania, ponieważ zwiększy to liczbę partii wierzchołków wysyłanych do GPU. Istnieje wiele rzeczy, które spowodują przerwanie partii, a główne z nich to tryby mieszania, zmiana shadera, zmiana uniformu na shader przed rysowaniem czegoś, a także rysowanie przy użyciu wbudowanych kształtów i prymitywów.
+Tak więc, jeśli masz kilka instancji pocisków, które rysują się przy użyciu trybu mieszania bm_add - na przykład - będziesz tworzyć nową vertex batch dla każdego z nich, co jest zdecydowanie złą rzeczą! Zamiast tego, miej kontroler object w swojej grze, który rysuje wszystkie pociski zamiast tego, jak to:
gpu_set_blendmode(bm_add);
with (obj_BULLET)
@@ -99,45 +116,45 @@
NOTE This doesn't just apply to using bm_add - any blending change will break the batch and will give a performance hit.
-In this way, all the bullets will be drawn in the same batch. Judicious use of the functions gpu_set_blendenable(), gpu_set_alphatestref(), and gpu_set_alphatestenable() can greatly improve performance and can be enabled/disabled as required throughout your project code, although they may not be appropriate for all types of graphics or projects.
-NOTE If you don't require the instance to draw itself when using a controller in this way then you can simply add a comment into the Draw Event to suppress the default drawing, or make the instance invisible (although this will prevent all code running for the instance in all draw events).
-Another way to reduce these numbers is to disable the Separate Texture Page option for sprites unless absolutely necessary. Each image stored in this way is sent to its own texture page and batched differently, so having these images on a regular texture page is better. You can then get the UVS coordinates using the sprite_get_uvs() function and store them in variables for use later. It may be a small amount of extra code, but the boost you will get is worth it. Note that this method will not permit texture repeats!
-As with all these tips, if it makes your life more difficult to change it and your game runs fine, don't worry about it too much...
-+
UWAGA To nie dotyczy tylko użycia bm_add - każda zmiana mieszania przerwie partię i spowoduje wzrost wydajności.
+W ten sposób wszystkie kule zostaną narysowane w tej samej partii. Rozsądne korzystanie z funkcji. gpu_set_blendenable(), gpu_set_alphatestref(), i gpu_set_alphatestenable() może znacznie poprawić wydajność i mogą być włączone/wyłączone w zależności od potrzeb w całym kodzie projektu, chociaż mogą nie być odpowiednie dla wszystkich rodzajów grafiki lub projektów.
+UWAGA Jeśli nie wymagasz, aby instancja rysowała się podczas używania kontrolera w ten sposób, wtedy możesz po prostu dodać komentarz do zdarzenia Draw, aby stłumić domyślne rysowanie, lub uczynić instancję niewidoczną (chociaż uniemożliwi to cały kod działający dla instancji we wszystkich zdarzeniach draw).
+Innym sposobem na zmniejszenie tych liczb jest wyłączenie opcji Oddzielna strona Texture dla sprites, chyba że jest to absolutnie konieczne. Każdy obraz przechowywany w ten sposób jest wysyłany na własną stronę texture i różnie pakowany, więc posiadanie tych obrazów na zwykłej stronie texture jest lepsze. Następnie możesz uzyskać współrzędne UVS używając funkcji sprite_get_uvs() i przechowywać je w zmiennych do późniejszego wykorzystania. Może to być niewielka ilość dodatkowego kodu, ale wzrost, który uzyskasz, jest tego wart. Zauważ, że ta metoda nie pozwoli na powtórzenia texture!
+Tak jak w przypadku wszystkich tych porad, jeśli utrudnia ci życie zmiana, a twoja gra działa dobrze, nie przejmuj się tym zbytnio...
+
Particles offer a very quick and efficient way to create dynamic effects in your game, and in general they give good performance. However, it's worth noting that using additive blending, alpha blending and colour blending on the particles may lower that performance, especially on mobile targets, so if you don't need it don't use it! Additive blending, in particular, can greatly increase the vertex batches and should be used with care.
-Note that on the non-WebGL HTML5 target, having multi-coloured, fading particles will require a lot of image caching and will be very slow. However, since particle sprites can be animated, you can create an animated sprite that has sub-images which change colour and then use that for the particle instead. It will still look like a gradual colour change, but not require the constant creation of cache images.
-You can find out more about particles from the page Guide To Using Particles.
-+
Cząstki oferują bardzo szybki i wydajny sposób tworzenia dynamicznych efektów w twojej grze i generalnie dają dobrą wydajność. Warto jednak zauważyć, że używanie additive blending, alpha blending i color blending na cząsteczkach może obniżyć tę wydajność, zwłaszcza na urządzeniach mobilnych, więc jeśli nie potrzebujesz tego, nie używaj! Additive blending, w szczególności, może znacznie zwiększyć partie wierzchołków i powinien być używany ostrożnie.
+Zauważ, że w przypadku nie-WebGL HTML5, posiadanie wielokolorowych, zanikających cząstek będzie wymagało dużego buforowania obrazu i będzie bardzo powolne. Jednakże, ponieważ cząstki sprites mogą być animowane, możesz stworzyć animowany sprite, który ma pod-obrazy, które zmieniają kolor, a następnie użyć go dla cząstki zamiast. Nadal będzie to wyglądać jak stopniowa zmiana koloru, ale nie będzie wymagać ciągłego tworzenia obrazów cache.
+Więcej o cząsteczkach można dowiedzieć się ze strony Przewodnik po używaniu cząsteczek.
+
Finally, we're going to touch briefly on using surfaces, as GameMaker has a fairly significant optimisation when using them in your games: the ability to switch on and off the depth buffer.
-When you just use surfaces as normal, GameMaker will actually create a surface and an accompanying depth buffer to ensure proper depth sorting when drawing anything in 3D. However, for most 2D games, this extra depth buffer is just not required and so is taking up extra memory space and processing time that could be used for other things. This is where the function surface_depth_disable() comes into play...
-This function can be called before you create a surface to disable the depth buffer generation, and all surfaces created afterwards will not have a depth buffer created for them. You can enable/disable this function as required, and can even call it once at the start of the game to disable depth buffers for all subsequent surface calls (and in most 2D games this is fine). It won't give a major performance boost, but it's certainly something to keep in mind if your game relies heavily on surfaces and might stop your game running out of memory on lower-specced devices.
+Na koniec poruszymy krótko temat używania powierzchni, ponieważ GameMaker posiada dość istotną optymalizację przy używaniu ich w swoich grach: możliwość switch włączania i wyłączania bufora głębi.
+Kiedy po prostu używasz powierzchni jak zwykle, GameMaker faktycznie stworzy powierzchnię i towarzyszącą jej głębię buffer, aby zapewnić prawidłowe sortowanie głębokości podczas rysowania czegokolwiek w 3D. Jednak w większości gier 2D, ta dodatkowa głębia buffer nie jest po prostu wymagana i zajmuje dodatkowe miejsce w pamięci i czas przetwarzania, który mógłby być wykorzystany do innych rzeczy. To właśnie tutaj funkcja surface_depth_disable() wchodzi w grę...
+Tę funkcję można wywołać przed utworzeniem powierzchni, aby wyłączyć generowanie głębi buffer, a wszystkie powierzchnie utworzone później nie będą miały utworzonej głębi buffer dla nich. Możesz włączyć/wyłączyć tę funkcję w zależności od potrzeb, a nawet możesz ją wywołać raz na początku gry, aby wyłączyć głębię buffers dla wszystkich kolejnych wywołań powierzchni (w większości gier 2D jest to w porządku). Nie spowoduje to znacznego wzrostu wydajności, ale z pewnością warto o tym pamiętać, jeśli Twoja gra w dużej mierze opiera się na powierzchniach i może powstrzymać grę przed wyczerpaniem pamięci na urządzeniach o niższej specyfikacji.
-
Apart from the main things mentioned above, there are other more general things that can help with performance and that are considered "good practices" too:
++
Oprócz głównych rzeczy wymienionych powyżej, istnieją inne bardziej ogólne rzeczy, które mogą pomóc w wydajności i które są również uważane za "dobre praktyki":
But, as we mentioned at the start of the page, all these optimisations are optional and if your game runs fine with 60 vertex batches, 80 texture swaps, additive blending, etc., then don't worry about it too much! Just keep these things in mind when programming your next game...
--
-
+
Ale, jak wspomnieliśmy na początku strony, wszystkie te optymalizacje są opcjonalne i jeśli twoja gra działa dobrze z 60 partiami wierzchołków, 80 texture swaps, additive blending, itp. to nie przejmuj się tym zbytnio! Po prostu pamiętaj o tych rzeczach podczas programowania następnej gry...
++
+
-
At the beginning of the computer era, binary and hex (hexadecimal) were a way of life, probably because high level languages (such as BASIC) were simply too slow to run. For example, multiplying 32 x 32 might have taken various CPU cycles to achieve using BASIC, but with binary it is done as a single operation in a single CPU cycle.
-These days however, with the power of even a basic PC, you no longer have to worry about this and you can do things the "long way", since the speed of the machine and its more complex CPU construction will make up for any short comings this approach has. This is great news of course, since it means that you no longer have to optimise every line of code you write, but if this is the case - should you really care about binary at all?
-The answer is definitely "yes, you should". While it's true you can still get some speed ups - and sometimes these can be significant - using binary and hex leads to a better understanding of how the CPU operates and can also lead to writing better code, being able to pack data better, and making some tasks a lot simpler. This page is going to explain a bit about what binary is as well as how it can be used when making your games.
-To write binary literals in GML, prefix them with 0b (e.g. 0b0010). See Data Types for more information.
-Let's look at the most basic binary theory first - how numbers are created. Take a look at this table:
+Na początku ery komputerów binarne i heksadecymalne (szesnastkowe) były sposobem na życie, prawdopodobnie dlatego, że języki wysokiego poziomu (takie jak BASIC) były po prostu zbyt wolne do uruchomienia. Na przykład pomnożenie liczby 32 x 32 w języku BASIC mogło zająć wiele cykli procesora, natomiast w języku binarnym jest to pojedyncza operacja wykonywana w jednym cyklu procesora.
+W dzisiejszych czasach, przy mocy nawet podstawowego komputera PC, nie trzeba się już o to martwić i można robić rzeczy "długą drogą", ponieważ szybkość maszyny i bardziej złożona konstrukcja procesora nadrobią wszelkie niedociągnięcia takiego podejścia. Jest to oczywiście wspaniała wiadomość, ponieważ oznacza, że nie trzeba już optymalizować każdej linijki kodu, który się pisze, ale jeśli tak jest, to czy w ogóle powinno się dbać o binarność?
+Odpowiedź brzmi zdecydowanie "tak, powinieneś". Prawdą jest, że nadal można uzyskać pewne przyrosty prędkości - a czasami mogą one być znaczące - ale używanie binarnego i szesnastkowego kodu prowadzi do lepszego zrozumienia sposobu działania procesora, a także może prowadzić do pisania lepszego kodu, lepszego pakowania danych i uproszczenia niektórych zadań. Ta strona wyjaśni nieco, czym jest binarność oraz jak można jej używać podczas tworzenia gier.
+Przyjrzyjmy się więc najpierw najbardziej podstawowej teorii binarnej - jak powstają liczby. Spójrzmy na tę tabelę:
000 = 0
001 = 1
010 = 2
100 = 4
Each 1 or 0 represents a single bit of data, and as you can see this means that in binary, 10 equals 2! Each bit is 2 times the previous value with the first bit being equal to 1. So bit 2 = 2, bit 3 = 4, bit 4 = 8 and so on (as shown below in this byte table):
+Każda 1 lub 0 reprezentuje jeden bit danych, a jak widać, oznacza to, że w systemie binarnym 10 równa się 2! Każdy bit jest 2 razy większy od poprzedniej wartości, przy czym pierwszy bit jest równy 1. Zatem bit 2 = 2, bit 3 = 4, bit 4 = 8 i tak dalej (jak pokazano poniżej w tabeli bajtów ):
00000001 = 1
00000010 = 2
00000100 = 4
@@ -33,74 +32,74 @@
That's fine if you want numbers that are a power of 2, but how do we create more complex numbers? Well a single binary number can only store a 0 or 1, and that's it, so for more complex numbers we need to add bits together. If for example we wanted to make 6, we would add 4 and 2 together like so.
+To dobrze, jeśli chcemy, aby liczby były potęgą dwójki, ale jak tworzyć bardziej złożone liczby? Cóż, pojedyncza liczba binarna może przechowywać tylko 0 lub 1, i to wszystko, więc aby uzyskać bardziej złożone liczby, musimy dodawać bity do siebie. Jeśli na przykład chcemy utworzyć liczbę 6, dodajemy do siebie 4 i 2 w następujący sposób.
00000010 = 2
00000100 = 4
00000110 = 6
This is true of all binary numbers, and how the computer makes up any number internally. Let's take a slightly more complicated number as a further example: 23. The number 23 is actually made up of 1+2+4+16 or 00010111. How about a much more complex example: 196? Well, that's made from 128+64+4 or 11000100. So actually it's not that complex really!
-If we start doing values outside of the range of a byte (which can store numbers from 0 to 255), it does start to get a little harder to track, however. For example, 217,361 is 110101000100010001 in binary. Or, 1+16+256+etc... The rules are the same no matter what the value being expressed is - each number is created from adding multiple bits together.
-Now, how do we perform mathematical operations on these values? Let's say you want to store true or false as a value. Usually compilers will use an INT (an INT is usually defined as a signed 32bit number - signed just means it can a positive or negative value, while unsigned means it can only be positive) and then simply assign it to 0 or 1. Having only 2 states, a true / false value is ideal to store in a bit, and if we did this we could store 32 true / false bits for each INT rather than just one, since an INT is made up of 32 bits.
-How would we do this? Well pretty easily it turns out:
+Dotyczy to wszystkich liczb binarnych oraz sposobu, w jaki komputer tworzy wewnętrznie każdą liczbę. Weźmy jako przykład nieco bardziej skomplikowaną liczbę: 23. Liczba 23 składa się w rzeczywistości z 1+2+4+16 lub 00010111. A co powiesz na znacznie bardziej skomplikowany przykład: 196? Cóż, ta liczba składa się z 128+64+4 lub 11000100. Tak więc w rzeczywistości nie jest ona aż tak skomplikowana!
+Jeśli jednak zaczniemy używać wartości spoza zakresu bajtu (który może przechowywać liczby z zakresu od 0 do 255), śledzenie ich stanie się nieco trudniejsze. Na przykład 217 361 to 110101000100010001 w systemie binarnym. Albo 1+16+256+etc... Zasady są takie same niezależnie od wyrażanej wartości - każda liczba jest tworzona przez dodanie do siebie wielu bitów.
+W jaki sposób można wykonywać operacje matematyczne na tych wartościach? Załóżmy, że chcesz zapisać true lub false jako wartość. Zazwyczaj kompilatory używają adresu INT (adres INT jest zwykle definiowany jako podpisana liczba 32-bitowa - podpisana oznacza, że może mieć wartość dodatnią lub ujemną, a niepodpisana, że tylko dodatnią), a następnie przypisują ją do adresu 0 lub 1. Mając tylko dwa stany, wartość true / false jest idealna do przechowywania w bicie, a gdybyśmy to zrobili, moglibyśmy przechowywać 32 bity true / false dla każdego adresu INT, a nie tylko jeden, ponieważ adres INT składa się z 32 bitów.
+Jak to zrobić? Okazuje się, że całkiem łatwo:
flags = flags | 1;
-The "|" operator is a bitwise OR, and this means the above instruction ORs 1 into the value held in the variable flags. If you remember from earlier, using a 1 will set the first bit. If we wanted to set the second bit, we would do this:
+Operator "|" jest operatorem bitowym OR, a to oznacza, że powyższa instrukcja ORs 1 do wartości przechowywanej w zmiennej flags. Jeśli pamiętasz z wcześniejszych lekcji, to użycie 1 spowoduje ustawienie pierwszego bitu. Gdybyśmy chcieli ustawić drugi bit, zrobilibyśmy to tak:
flags = flags | 2;
-We OR in 2, because the bit pattern 00000010 is equal to 2. So what exactly does the binary OR operator do? Well, it merges all the bits together into a single value, like this:
+Na stronie OR znajduje się 2, ponieważ wzór bitowy 00000010 jest równy 2. Co dokładnie robi operator binarny OR? Łączy wszystkie bity w jedną wartość, na przykład tak:
010110100 // Value 1
110011001 // value 2
110111101 // Value 1 OR Value 2
Here's what's known as a truth table for the OR operator:
+Oto tzw. tabela prawdy dla operatora OR:
00 | 00 = 00
00 | 01 = 01
01 | 01 = 01
01 | 00 = 01
So where there is a value with 2 zeros, it'll stay zero. The advantage of using bits like this as a true/false state, is they you can set several bits as "flags" in one operation, something you simply couldn't do with a normal boolean value. For example, let's say bit 1 is an "active" flag, and bit 3 is a "visible" flag. We could set both by doing this:
+Zatem tam, gdzie jest wartość z dwoma zerami, pozostanie ona zerem. Zaletą używania takich bitów jako stanów true/false jest to, że można ustawić kilka bitów jako "flagi" w jednej operacji, czego nie można zrobić z normalną wartością logiczną. Na przykład, powiedzmy, że bit 1 jest "aktywny" flag, a bit 3 jest "widoczny" flag. Możemy ustawić obie te wartości w ten sposób:
flags = flags | 5;
-This is because 5 is 00000101 in binary, and following the rule above, the variable "flags" will get both these 2 bits merged with its own. So even if bit 1 was already set, the operation still works and bit 3 will now also be set.
-What about clearing flags? Well this is where the bitwise "&" AND operation comes in. When you AND something, the bits that are set in the mask are kept, while the bits that are clear in the mask, are removed - like this:
+Dzieje się tak, ponieważ 5 to 00000101 w systemie binarnym, a zgodnie z powyższą regułą zmienna "flagi" otrzyma oba te bity połączone ze swoimi własnymi. Zatem nawet jeśli bit 1 był już ustawiony, operacja nadal działa, a bit 3 również zostanie ustawiony.
+A jak wyczyścić stronę flags? W tym miejscu można skorzystać z operacji bitowej "&" AND. Kiedy AND czegoś, bity, które są ustawione w masce, są zachowywane, a bity, które są czyste w masce, są usuwane - w ten sposób:
01110010101 // Value 1
00110000100 // Value 2
00110000100 // Value 1 AND value 2
As you can see, where there is a 1 in each value, the 1 is kept, and where there is a mix or 0's and 1's these are reset to 0. Here's the truth table for ANDing:
+Jak widać, tam, gdzie w każdej wartości jest 1, ta 1 jest zachowywana, a tam, gdzie jest mieszanina 0 i 1, te wartości są resetowane do 0. Oto tabela prawdy dla strony ANDing:
00 & 00 = 00
01 & 00 = 00
00 & 01 = 00
01 & 01 = 01
So, only when there is a bit in each place will it be kept. What this means, is that just as you are able to set multiple flags at once, you can also clear multiple flags at once. For example, let's take the case above, but this time clear them. We want to clear bits 1 and 3 (giving us the value 5), but in remembering the truth table above, what we want to do is keep all the other bits, and clear bits 1 and 3. This would be a binary "mask" of 11111111111111111111111111111010 (32bits). This mask keeps all bits currently set, but clears the two bits we actually want cleared. So if had a value of 1000111011 and I wanted to clear bits 1 and 3 using the mask above, it would end up as this...
+Tak więc tylko wtedy, gdy w każdym miejscu znajduje się jakiś fragment, zostanie on zachowany. Oznacza to, że tak samo jak można ustawić wiele stron flags jednocześnie, można również wyczyścić wiele stron flags jednocześnie. Na przykład, weźmy powyższy przypadek, ale tym razem wyczyśćmy je. Chcemy wyczyścić bity 1 i 3 (co da nam wartość 5), ale pamiętając o powyższej tabeli prawdy, chcemy zachować wszystkie pozostałe bity i wyczyścić bity 1 i 3. W ten sposób powstanie binarna "maska" o wartości 11111111111111111111111111111010 (32 bity). Ta maska zachowuje wszystkie aktualnie ustawione bity, ale czyści dwa bity, które mają być wyczyszczone. Gdybyśmy więc mieli wartość 1000111011 i chcieli wyczyścić bity 1 i 3 za pomocą powyższej maski, otrzymalibyśmy następujący wynik...
00000000000000000000001000111011 // Value
11111111111111111111111111111010 // Mask
00000000000000000000001000111010 // Value AND Mask
This is great, but if we had to work this out every time we needed to clear flags, it would become tiresome. What we need is a way to flip bits easily (and preferably without CPU cost). Fortunately there is an easy way of doing this by using the " ~" NOT operator.
-The NOT operator is just what it says - not those bits. Here's a truth table for NOT.
+Jest to świetne rozwiązanie, ale gdybyśmy musieli to robić za każdym razem, gdy chcemy wyczyścić stronę flags, stałoby się to męczące. Potrzebujemy sposobu na łatwe przerzucanie bitów (i najlepiej bez kosztów dla procesora). Na szczęście istnieje prosty sposób, aby to zrobić, wykorzystujący operator " ~" NOT.
+Operator NOT jest dokładnie tym, co mówi - nie tymi bitami. Oto tabela prawdy dla NOT.
~00 = 11
~01 = 10
~10 = 01
~11 = 00
This operator makes removing flags very simple, and better yet, it's usually a compile time optimisation meaning if you're using a constant number (i.e. not a variable) then the compiler will flip the bits automatically for you. Take this statement where we want to clear bits 1 and 3 again:
+Ten operator sprawia, że usuwanie flags jest bardzo proste, a co więcej, jest to zazwyczaj optymalizacja w czasie kompilacji, co oznacza, że jeśli używasz stałej liczby (tzn. nie zmiennej), to kompilator automatycznie odwróci bity za Ciebie. Weźmy na przykład poniższą instrukcję, w której chcemy ponownie wyczyścić bity 1 i 3:
a = a & ~5;
-This will actually compile down to just "a & 11111111111111111111111111111010". This makes life pretty simple in terms of clearing flags.
-The last operator we want to look at is "^" EOR (Exclusive OR, sometimes called XOR), this operator flips the bits set in both values. Here's the EOR truth table:
+W rzeczywistości skompiluje się on do postaci "a & 11111111111111111111111111111010". To bardzo upraszcza życie, jeśli chodzi o usuwanie flags.
+Ostatnim operatorem, któremu chcemy się przyjrzeć, jest "^" EOR (Exclusive OR, czasami nazywany XOR), operator ten odwraca bity ustawione w obu wartościach. Oto tabela prawdy EOR:
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
This is a curious one, but incredibly useful. For example, let's say we want a counter that simply counts from 0 to 1 and back to 0 (toggling between 0 and 1), we could add one and do an IF to see if it's gotten to 2, and then reset it back to 1. Or...we could add 1 and then AND it with 1 (since 01+01 = 10, and 10 & 01 = 0) or we can do this:
+Jest to bardzo ciekawe, ale niezwykle użyteczne rozwiązanie. Na przykład, powiedzmy, że chcemy mieć licznik, który po prostu liczy od 0 do 1 i z powrotem do 0 (przełączając się między 0 a 1), możemy dodać jeden i wykonać IF, aby sprawdzić, czy doszedł do 2, a następnie zresetować go z powrotem do 1. Albo... możemy dodać 1, a następnie AND ją z 1 (ponieważ 01+01 = 10, oraz 10 & 01 = 0) lub możemy zrobić tak:
a = a ^ 1;
-What this does the first time it's run is 0 ^ 1 = 1, then the second time 1 ^ 1 = 0, thereby toggling things back and forth from 0 to 1.
-So - OR (|), AND(&), NOT(~) and EOR(^) let us manipulate bits with relative ease, allowing us, at the simplest level, to control multiple bits at once. We can obviously use these operations for other things when developing our games, like masking sprites, doing integer MOD operations (using AND) or doing nice looping counters.
-So, we can do simply bitwise operations, but let's look at the more complex stuff, starting with the question, how does a computer add? Let's look at a very simple example: 1+1.
+Przy pierwszym uruchomieniu jest to 0 ^ 1 = 1, a przy drugim 1 ^ 1 = 0, co powoduje zmianę wartości z 0 na 1.
+Tak więc - OR (|), AND(&), NOT(~) i EOR(^) pozwalają nam stosunkowo łatwo manipulować bitami, umożliwiając, na najprostszym poziomie, kontrolowanie wielu bitów naraz. Podczas tworzenia gier możemy oczywiście używać tych operacji do innych rzeczy, takich jak maskowanie sprites, wykonywanie operacji na liczbach całkowitych MOD (przy użyciu AND) lub wykonywanie ładnych liczników w pętli.
+Potrafimy więc wykonywać proste operacje bitowe, ale przyjrzyjmy się bardziej złożonym zagadnieniom, zaczynając od pytania: jak komputer dodaje? Przyjrzyjmy się bardzo prostemu przykładowi: 1+1.
00000001
00000001
00000010
Just like normal additions, we add numbers together and then we overflow into the next column, but unlike a normal decimal addition, we can only go from 0 to 1, not 0 to 9. So adding a 1+1 means we overflow into 10. So let's look at a more complex example.
+Podobnie jak w normalnym dodawaniu, dodajemy liczby do siebie, a następnie przelewamy do następnej kolumny, ale w przeciwieństwie do normalnego dodawania dziesiętnego, możemy przejść tylko od 0 do 1, a nie od 0 do 9. Zatem dodanie liczby 1+1 oznacza przepełnienie do 10. Przyjrzyjmy się więc bardziej złożonemu przykładowi.
01011011 = 91
00101101 = 45
10001000 = 136
It's obviously harder to see here, but the overflows ripple along until there are no ones in a column. It's worth noting, that computers can only add (or subtract, multiply or divide) 2 numbers at once. Take 19 + 19 + 19. Being human, we can add all the 9's together, carry the 2 and then on we go! But computers can't do that - what they can do is this: (19 + 19) + 19. So they'll do each calculation in blocks of 2.
-The binary calculations that are of most interest to us as programmers are multiplication and division. Computers only multiply in 2s, and to do more it'll break a number apart, and then add all the results together. Let's take some very simple examples first. 4 * 2 = 8. Now to multiply by 2 in binary, we shift all the bits to the LEFT by one. Like this:
+Oczywiście tutaj jest to trudniej zauważyć, ale przepełnienia pojawiają się stopniowo, aż do momentu, gdy w danej kolumnie nie ma jedynek. Warto zauważyć, że komputery mogą dodawać (lub odejmować, mnożyć lub dzielić) tylko dwie liczby jednocześnie. Weźmy przykład 19 + 19 + 19. Będąc człowiekiem, możemy dodać do siebie wszystkie 9, przenieść 2 i dalej działać! Ale komputery tego nie potrafią - potrafią natomiast zrobić to: (19 + 19) + 19. Dlatego każde obliczenie wykonują w blokach po 2.
+Obliczenia binarne, które najbardziej interesują nas jako programistów, to mnożenie i dzielenie. Komputery mnożą tylko dwójkami, a żeby wykonać więcej, rozbijają liczbę na części, a następnie dodają wszystkie wyniki do siebie. Przyjrzyjmy się najpierw kilku bardzo prostym przykładom. 4 * 2 = 8. Aby pomnożyć liczbę przez 2 w układzie binarnym, należy przesunąć wszystkie bity w lewo o jeden. Na przykład tak:
00000100 * 2 = 00001000 = 8
-All the bits in this case have moved to the left by one, making it move from the 3rd bit, to the 4th, and changing the value from 4 to 8. How about a larger number?
+W tym przypadku wszystkie bity przesunęły się w lewo o jeden, co spowodowało przesunięcie z trzeciego bitu na czwarty i zmianę wartości z 4 na 8. A co powiesz na większą liczbę?
101 = 01100101 * 2 = 11001010 = 202
-Again, all the bits move on one, and that multiples by 2. So, how about a multiple by 4? Easy, we shift everything left by 2, rather than one. So how about 16, or 128? This would require a left shift of 4 bits, or 7 bits respectively. This is incredibly useful; it means we can do simple multiplications by simply moving bits around. To do this, we use the left shift operator <<. Here are some examples:
+Ponownie wszystkie bity przesuwają się o jeden, a to mnoży się przez 2. A co z mnożeniem przez 4? To proste, przesuniemy wszystko w lewo o 2, a nie o jeden. A więc co powiesz na 16 lub 128? Wymagałoby to przesunięcia w lewo odpowiednio o 4 bity lub 7 bitów. Jest to niezwykle użyteczne, ponieważ dzięki temu możemy wykonywać proste mnożenia, przesuwając bity. W tym celu używamy operatora przesunięcia w lewo <<. Oto kilka przykładów:
00000001 << 1 = 000000010 = 2
00000001 << 2 = 000000100 = 4
00000001 << 3 = 000001000 = 8
@@ -109,99 +108,99 @@
Now, aside from being very useful for fast/simple multiplications, it's also very useful for setting specific bits, without having to figure out the bit value. Let's say we wanted to set bit 27, what number is that? (67108864 by the way!), well we can use the syntax above to easily set flags like this:
+Oprócz tego, że jest to bardzo użyteczne do szybkiego i prostego mnożenia, jest to również bardzo użyteczne do ustawiania konkretnych bitów, bez konieczności ustalania ich wartości. Załóżmy, że chcemy ustawić bit 27, co to za liczba? (67108864 przy okazji!), więc możemy użyć powyższej składni, aby łatwo ustawić flags w ten sposób:
a = a | (1 << 27)
-Okay... so actually this would be bit 26 the way we've been describing things so far (as bits have been starting at one), but actually... bits start at bit 0, and go upwards, not at bit 1. So while there are 32 bits in an INTEGER, the bits range from 0 to 31, not 1 to 32. This is actually pretty useful, as we can now set up constants for bit numbers.
-So let's say Bit 27 is an active flag, and bit 0 is an exploding flag. How can we set both?
+Ok... więc właściwie byłby to bit 26, tak jak opisywaliśmy to do tej pory (ponieważ bity zaczynały się od jedynki), ale tak naprawdę... bity zaczynają się od bitu 0 i idą w górę, a nie od bitu 1. Tak więc, choć w liczbie INTEGER są 32 bity, to są to bity z zakresu od 0 do 31, a nie od 1 do 32. Jest to całkiem przydatne, ponieważ możemy teraz ustawić stałe dla liczb bitowych.
+Załóżmy więc, że bit 27 to aktywny flag, a bit 0 to eksplodujący flag. Jak możemy ustawić oba?
ACTIVE = 27;
BOOM = 0;
A = A | (1 << ACTIVE) | (1 << BOOM);
This may look like a lot of code, but if these numbers are constants, the compiler will pre-compile these operations into a single value so that we end up with this as actual code.
+Może to wyglądać na dużą ilość kodu, ale jeśli liczby te są stałe, kompilator wstępnie skompiluje te operacje w jedną wartość, dzięki czemu otrzymamy taki właśnie kod.
A = A | 13421772;
-Clearing these bits (as we saw above) is simply a matter of using the NOT modifier, like this:
+Usuwanie tych bitów (jak widzieliśmy powyżej) polega po prostu na użyciu modyfikatora NOT, jak poniżej:
A = A & ~((1 << ACTIVE) | (1 << BOOM));
-So this happily lets us set and clear any bits we'd like, and it also lets us compress out data structures massively. Compressing data structures is a good thing, because if you use less memory, you get less cache misses, and your code just runs faster. Put it this way, what's quicker, copying 32Mb or data, or 4Mb? Well, quite clearly 4 is. So if you can pack all yours flags down into a single memory access, this is good!
-Now, let's take a quick look at how you do division, and why it's going to be so useful. Division is done by shifting the bits right using the right shift operator >>. Let's take a simple number - 64 - and divide it by 32:
+Dzięki temu możemy ustawiać i czyścić dowolne bity, a także kompresować struktury danych na ogromną skalę. Kompresja struktur danych to dobra rzecz, ponieważ jeśli używasz mniej pamięci, masz mniej cache misses, a twój kod po prostu działa szybciej. Jakby to ująć, co jest szybsze: kopiowanie 32 MB danych czy 4 MB? Cóż, z całą pewnością 4 jest szybsze. Jeśli więc możesz zmieścić wszystkie swoje flags w jednym dostępie do pamięci, to dobrze!
+Przyjrzyjmy się teraz, w jaki sposób wykonuje się dzielenie i dlaczego jest ono tak przydatne. Dzielenie wykonuje się przez przesunięcie bitów w prawo za pomocą operatora przesunięcia w prawo >>. Weźmy prostą liczbę - 64 - i podzielmy ją przez 32:
64 / 32 = 01000000 >> 5 = 00000010
-So there you shift the single bit down by 5 (which is the number of shifts required for 32 – look above), which gives us 2. But what happens if here are other bits in there? Well let's take a look:
+W tym przypadku przesuwamy pojedynczy bit w dół o 5 (tyle właśnie przesunięć potrzeba do uzyskania liczby 32 - patrz wyżej), co daje nam 2. Ale co się stanie, jeśli w tym miejscu są inne bity? Przyjrzyjmy się temu:
68 / 32 = 01000100 >> 5 = 00000010
-So there you go…. It's exactly the same. The bits we shift down are simply lost. This is actually really useful, because when dividing down if we need the remainder, there's an even easier way to get it, which we'll get to in a moment. But first, let's take a practical example. I have an X and Y position, and I want to get the grid cell this falls in, where the grid is 32x32 in size. This method allows is to store objects, collisions, flags – all manner of things, and access them very quickly. So here we go:
+No i proszę: .... Jest dokładnie tak samo. Bity, które przesuwamy w dół, są po prostu tracone. Jest to bardzo przydatne, ponieważ przy dzieleniu w dół, jeśli potrzebujemy reszty, istnieje jeszcze prostszy sposób na jej uzyskanie, o czym za chwilę. Ale najpierw posłużmy się praktycznym przykładem. Mam pozycję X i Y i chcę uzyskać komórkę siatki, w której się ona znajduje, przy czym siatka ma rozmiar 32x32. Metoda ta umożliwia przechowywanie danych objects, kolizje, flags - wszelkiego rodzaju rzeczy - i bardzo szybki dostęp do nich. A więc zaczynamy:
var X_index = x >> 5;
var Y_index = y >> 5;
cell_data = mygrid[# X_index,Y_index];
So, what if we wanted the remainder? Perhaps this remainder is used as some kind of order flag or something. Whatever the reason, getting a remainder is as simple as doing an AND:
+Co by było, gdybyśmy chcieli otrzymać resztę? Być może ta reszta jest używana jako pewnego rodzaju zamówienie flag lub coś w tym rodzaju. Niezależnie od powodu, uzyskanie reszty jest tak proste, jak wykonanie polecenia AND:
var remainder = x & 31
var X_Index = x >> 5;
Now, you might have noticed we've used multiple lines of code here (as is so often the case), but this is still only a couple of very fast instructions. But why the 31? Well, as bit 5 is 32, then all the bits below would be 31, and that's the maximum remainder so that's what we AND with (we could also use (1 << 5) - 1 which would make 32 - 1 = 31). Now, if I were to do this without understanding binary, it would look like this:
+Być może zauważyłeś, że użyliśmy tu wielu wierszy kodu (jak to często bywa), ale to wciąż tylko kilka bardzo szybkich instrukcji. Ale dlaczego 31? Ponieważ bit 5 ma wartość 32, to wszystkie bity poniżej będą miały wartość 31, a to jest maksymalna reszta, więc z taką właśnie resztą wchodzimy na stronę AND (moglibyśmy też użyć (1 << 5) - 1, co dałoby 32 - 1 = 31). Gdybym miał to zrobić, nie rozumiejąc zasad działania binarnego, wyglądałoby to tak:
var r = x mod 32;
var X_Index = floor(x / 32);
So why is this much worse? Well, in order to divide by 32, we have to execute a floating point divide - which obviously takes time, but in order to do the mod 32, you actually have to do another one! If we were doing this in assembler, we actually get BOTH values in one divide, but you don't get this in high level languages (well… not very often), and so you have to do all the work twice. This adds up, especially if you're doing a tight loop with lots of calculations like this. Integer divides using bit shifting as shown above really help optimising your game.
-Since this can be quite a complex concept to grasp and then apply to real-world programming situations, you can find below a series of short examples that could be applied to any game made with GameMaker.
- +Dlaczego więc jest to o wiele gorsze? Otóż, aby podzielić przez 32, musimy wykonać dzielenie zmiennoprzecinkowe - co oczywiście zajmuje czas, ale aby wykonać mod 32, trzeba wykonać jeszcze jedno dzielenie! Gdybyśmy robili to w asemblerze, otrzymalibyśmy obie wartości w jednym dzieleniu, ale w językach wysokiego poziomu nie jest to możliwe (cóż... niezbyt często), więc trzeba wykonać całą pracę dwukrotnie. Jest to bardzo uciążliwe, zwłaszcza jeśli na stronie loop wykonuje się wiele takich obliczeń. Dzielenie liczb całkowitych z wykorzystaniem przesunięcia bitowego, jak pokazano powyżej, naprawdę pomaga w optymalizacji gry.
+Ponieważ pojęcie to może być dość skomplikowane do zrozumienia, a następnie zastosowania w rzeczywistych sytuacjach programistycznych, poniżej znajdziesz serię krótkich przykładów, które można zastosować w dowolnej grze stworzonej za pomocą GameMakera.
+GameMaker developers often use the function place_free(), and then when a collision is found, try to slowly move the object out by either looping around an x or y position while continuing to execute that function, or by using the move_outside_all() function.
-So, what's the faster way to do this? Well, if we use proper power-of-2 tiles, then we have a very simple method that's also lightning fast. If we are moving right, and we've moved into a collision block, then as we know everything is aligned to 32, so we need to also align the sprite to a 32 pixel boundary - preferably the one to the left - so the sprite is moved OUT of the collision. This is really easy, knowing the rules we've used above to get the remainder, and knowing how to get the inverse of bits, we can simply do this:
+ProgramiściGameMakera często używają funkcji place_free(), a następnie po wykryciu kolizji próbują powoli przesunąć stronę object na zewnątrz, wykonując pętlę wokół pozycji x lub y, kontynuując wykonywanie tej funkcji, albo używając funkcji move_outside_all().
+Jaki jest więc szybszy sposób na wykonanie tej operacji? Cóż, jeśli użyjemy odpowiedniej potęgi 2 tiles, to mamy bardzo prostą metodę, która jest jednocześnie błyskawiczna. Jeśli poruszamy się w prawo i weszliśmy w blok kolizji, to jak wiemy, wszystko jest wyrównane do 32, więc musimy również wyrównać adres sprite do granicy 32 pikseli - najlepiej tej po lewej stronie - tak aby adres sprite został przesunięty poza obszar kolizji. Jest to naprawdę proste, ponieważ znając zasady, których użyliśmy powyżej do uzyskania reszty, oraz wiedząc, jak uzyskać odwrotność bitów, możemy po prostu wykonać tę czynność:
x = x & ~31;
-That's right, that's ALL that it takes to align to a 32 pixel boundary. By changing the 31 we can align to anything we like – as long as it's a power of 2. (This is the equivalent of dividing by 32, then multiplying by 32, thereby removing the lower bits.)
-If we wanted to align to the right, then we'd do the above, but then add 32 to move it into the next tile. Simple. All this makes the whole collision code monumentally faster, and lets you spend the CPU time where you really need it.
-+
Zgadza się, to WSZYSTKO, co jest potrzebne do wyrównania do granicy 32 pikseli. Zmieniając liczbę 31, możemy wyrównać do czegokolwiek chcemy - pod warunkiem, że jest to potęga 2. (Jest to odpowiednik dzielenia przez 32, a następnie mnożenia przez 32, co powoduje usunięcie niższych bitów).
+Jeśli chcemy wyrównać do prawej, wykonujemy powyższą czynność, ale dodajemy 32, aby przesunąć ją na następną stronę tile. Proste. Wszystko to sprawia, że cały kod kolizji jest znacznie szybszy i pozwala wykorzystać czas procesora tam, gdzie jest on naprawdę potrzebny.
+
Say you have a level with a few doors, and a key for each. How can you easily mark a key for a specific door? Well, normally you'd just assign an ID to the key and the door. So what if you wanted a key to open 2 or 3 doors? Easy. You use a MASK. The door would have a single bit assigned like so:
-
Załóżmy, że masz poziom z kilkoma drzwiami i kluczem do każdego z nich. W jaki sposób można łatwo oznaczyć klucz do konkretnych drzwi? Cóż, normalnie wystarczy przypisać identyfikator do klucza i drzwi. A jeśli chcesz, aby jeden klucz otwierał 2 lub 3 drzwi? To proste. Używasz MASKI. Drzwi będą miały przypisany jeden bit w następujący sposób:
+
door_id = 1; // 0001
-The others would be something like:
-
Inne to na przykład:
+
door_id=2; // 0010
door_id=4; // 0100
door_id=8; // 1000
etc...
If we wanted the key to open door 1 and 3, then the key would have the MASK value of 5 (which is 101 in binary). If we perform an AND of this, and it comes out "not zero", then we know that the key can open the door. You could also have keys that opened nothing by having a MASK of 0. See the code below for the actual check:
+Gdybyśmy chcieli, aby klucz otwierał drzwi 1 i 3, wówczas klucz miałby wartość MASK równą 5 (czyli 101 w systemie binarnym). Jeśli sprawdzimy to na stronie AND i wyjdzie nam "nie zero", to wiemy, że klucz może otworzyć drzwi. Można też mieć klucze, które nic nie otwierają, mając wartość MASK równą 0. Zobacz poniższy kod, aby sprawdzić, jak to działa:
if ((key_id & door_id) ! = 0)
{
opendoor();
}
+
Let's say we want a simple animation counter, going from 0 to to 15 (as we have 16 frames of animation). Normally you would do an increment, and then do an if check to wrap the number, but for this example let's use the AND(&) operator:
+Załóżmy, że chcemy mieć prosty licznik animacji, od 0 do 15 (ponieważ mamy 16 klatek animacji). Normalnie wykonalibyśmy inkrementację, a następnie sprawdzenie if, aby zawinąć liczbę, ale w tym przykładzie użyjmy operatora AND(&):
counter = (counter + 1) & 15;
-Since 16 is a power of 2, we can reduce that number by 1 and use it as a mask, which we can then use to wrap our counter value. If the counter moves up from 15 to 16, we end up with bit pattern 10000, and if we AND that with 15 (bit pattern 01111) we end up with 00000 (simply zero). This means that the above code is useful for wrapping values within the range of a power of 2.
-+
Ponieważ 16 jest potęgą 2, możemy zmniejszyć tę liczbę o 1 i użyć jej jako maski, którą następnie możemy wykorzystać do zawijania wartości naszego licznika. Jeśli licznik przesunie się w górę z 15 do 16, to otrzymamy bitowy wzorzec 10000, a jeśli AND to z 15 (bitowy wzorzec 01111), to otrzymamy 00000 (po prostu zero). Oznacza to, że powyższy kod jest przydatny do zawijania wartości w zakresie potęgi 2.
+
What if you wanted to check to see if something was a power of 2? Well, here's a neat little trick.. This will return true if the given value is a power of 2:
+A gdybyś chciał sprawdzić, czy coś jest potęgą dwójki? Oto mała, zgrabna sztuczka... Funkcja zwróci wynik true, jeśli podana wartość jest potęgą 2:
function is_pow2(_val)
{
return _val & (_val - 1)) == 0;
}
So if we had the number 51 (110011) what does this do? Well, we get this... 110011 & 110010, which obviously leaves us with false, as there are lots of bits left after the AND. If we had 64 (1000000), then it becomes this... 1000000 & 0111111 which does leave us 0, so it's true.
-+
Jeśli więc mamy liczbę 51 (110011), co to oznacza? Cóż, otrzymamy to... 110011 & 110010 co oczywiście pozostawia nam false, ponieważ po AND pozostało jeszcze wiele bitów. Jeśli mielibyśmy 64 (1000000), to otrzymalibyśmy to... 1000000 & 0111111, co jednak pozostawia nam 0, więc jest to true.
+
Here's a quick bit of code to align to power of 2 numbers. (1,2,4,8,16 and so on). This can be very useful for memory allocation, or making sure you write data to proper boundaries. In this example, _val1 needs to be aligned to _val2 bytes, where _val2 is a power of 2 number. This little function rounds UP to the next boundary of the desired number.
+Oto krótki fragment kodu do wyrównywania do potęgi 2 liczb. (1,2,4,8,16 i tak dalej). Może to być bardzo przydatne podczas alokacji pamięci lub upewniania się, że dane są zapisywane w odpowiednich granicach. W tym przykładzie adres _val1 musi być wyrównany do _val2 bajtów, gdzie _val2 jest potęgą liczby 2. Ta mała funkcja zaokrągla w górę do następnej granicy żądanej liczby.
function align_pow2(_val1, _val2)
{
return _val1 + (_val2 - 1)) & ~(_val2 - 1);
}
-
+
+
-
-
+
+
+
-
When you are importing a project from a previous version of GameMaker you may see that the project has compatibility scripts added. In general, these scripts use the updated GameMaker Language (GML) functions - to convert obsolete functions into the new way of doing things, and are a great way to learn how things should be done in GameMaker. However, there are a few functions that are used for compatibility only that should not be used - anywhere else, and certainly not in your own projects. To help you identify these compatibility functions they are listed here, but we must stress that they should never be used outside of compatibility scripts:
+Podczas importowania projektu z poprzedniej wersji GameMaker możesz zauważyć, że do projektu zostały dodane skrypty zgodności. Ogólnie rzecz biorąc, te skrypty scripts używają zaktualizowanych funkcji GameMaker Language (GML) + do konwersji przestarzałych funkcji na nowy sposób robienia rzeczy i są świetnym sposobem na nauczenie się, jak powinno się to robić w GameMakerze. Istnieje jednak kilka funkcji, które są używane wyłącznie w celu zapewnienia kompatybilności i nie powinny być używane + nigdzie indziej, a już na pewno nie w swoich własnych projektach. Aby ułatwić Ci identyfikację tych funkcji, wymieniono je tutaj, ale musimy podkreślić, że nigdy nie należy ich używać poza skryptami kompatybilności:
-
-
+
+
+
-
For those users coming from previous versions of GameMaker, it may be a bit confusing using GameMaker at first since there have been a number of changes made to the way that project assets, editing and coding are handled. These changes mean - that the neither the IDE nor the GameMaker Language (GML) supports the items listed below. However, that does not mean that you - cannot import games made with previous versions into GameMaker, as you can. GameMaker will automatically convert all legacy functions into compatibility scripts, which are scripts containing functions that convert - the legacy methods into the updated methods.
-What happens is that GameMaker will parse your project for all the obsolete functions and variables that you have used, and then create a series of scripts using those function names. These scripts will contain either the new equivalent - runtime function or a short script function that performs the same action as the obsolete function.
-When you first import a GameMaker project you will be shown a compatibility report much like this one:
-The main body of the report shows which objects and scripts have been affected and where, while at the end - you can find a list of the scripts that have been created for your project. You can click the middle mouse button or press on any of the scripts listed in the report to open it and see what has been done.
-Note that if you see any scripts created with a double under-bar before their name (for example: __global_object_depths), then these are scripts that have been created by the IDE to help with compatibility and are not scripts - that have been converted from obsolete functions, so these should not be tampered with as they are required for the other compatibility scripts to work.
-When you have finished revising the compatibility report you can close the workspace, but should you need to revise anything within the report you can find it again by going to the Notes section of the - Asset Browser.
-Note that you can keep using these compatibility scripts just as you would have used the functions in the legacy version of GameMaker, however, due to the way they work, there will be a performance impact associated with this. We recommend that you - update projects to directly use the new methods and remove the compatibility scripts if you can, as it will improve performance and also give you an insight into the way that GameMaker and the GameMaker Language works compared to legacy products.
-Also note that there are some functions that have been introduced to the GameMaker Language to ensure compatibility with older projects and that will appear in these compatibility scripts. However these functions should never be used in your own projects. - You can find a list of these functions from the following section of the manual:
+Użytkownicy korzystający z poprzednich wersji programu GameMaker mogą być na początku nieco zdezorientowani, ponieważ w GameMakerze wprowadzono szereg zmian w sposobie obsługi projektu assets, edycji i kodowania. Zmiany te oznaczają, że + że ani IDE, ani język GameMaker Language (GML) nie obsługują elementów wymienionych poniżej. Nie oznacza to jednak, że + że nie możesz importować do programu GameMaker gier stworzonych w poprzednich wersjach, ponieważ możesz. GameMaker automatycznie przekształci wszystkie starsze funkcje w skrypty zgodności, które są scripts zawierające funkcje konwertujące + które konwertują starsze metody na metody zaktualizowane.
+GameMaker sprawdzi projekt pod kątem wszystkich przestarzałych funkcji i zmiennych, których używałeś, a następnie utworzy serię stron scripts z nazwami tych funkcji. Te scripts będą zawierać albo nowy odpowiednik + lub krótką funkcję skryptu, która wykonuje to samo działanie, co przestarzała funkcja.
+Podczas pierwszego importowania projektu GameMakera zostanie wyświetlony raport zgodności, podobny do tego:
+W głównej części raportu pokazano, które strony objects i scripts zostały dotknięte i gdzie, a na końcu + znajduje się lista stron scripts, które zostały utworzone dla danego projektu. Aby otworzyć raport i zobaczyć, co zostało zrobione, można kliknąć środkowy przycisk myszy lub nacisnąć przycisk na dowolnej stronie scripts wymienionej w raporcie.
+Zwróć uwagę, że jeśli zobaczysz stronę scripts z podwójną kreską przed nazwą (na przykład: __global_object_depths), to są to skrypty scripts, które zostały utworzone przez IDE w celu zapewnienia kompatybilności, a nie skrypty + które zostały przekonwertowane z przestarzałych funkcji, więc nie należy w nie ingerować, ponieważ są one wymagane do działania innych kompatybilnych scripts.
+Po zakończeniu zmiany raportu zgodności można zamknąć stronę workspace, ale jeśli zajdzie potrzeba zmiany czegokolwiek w raporcie, można to ponownie znaleźć, przechodząc do sekcji Uwagi w + Przeglądarka zasobów.
+Należy pamiętać, że można nadal używać tych funkcji scripts tak samo, jak w starszej wersji GameMaker, jednak ze względu na sposób ich działania będzie to miało wpływ na wydajność. Zalecamy, aby + zaktualizować projekty tak, by bezpośrednio korzystały z nowych metod i usunąć kompatybilność scripts, jeśli to możliwe, ponieważ poprawi to wydajność, a także da Ci wgląd w sposób, w jaki działa GameMaker i GameMaker Language w porównaniu ze starszymi produktami.
+Należy również pamiętać, że istnieją pewne funkcje, które zostały wprowadzone do GameMaker Language w celu zapewnienia kompatybilności ze starszymi projektami i które pojawią się w tej kompatybilności scripts. Funkcji tych nie należy jednak nigdy używać we własnych projektach. + Listę tych funkcji można znaleźć w następującej części podręcznika:
-You can also find a complete list of all the obsolete functions that have equivalent compatibility scripts created for them from the following page:
+Na poniższej stronie znajduje się również pełna lista wszystkich przestarzałych funkcji, dla których utworzono odpowiedniki kompatybilności scripts:
--
-
+
+
+
-
This section covers all the errors you may get for your game's GML code.
-The first form of error reporting is the Syntax Error. This is an error in your code that GameMaker has caught before you have tried to compile it and these will be shown in the IDE, either in the code editor or in the Syntax Errors Output Window:
-The next level of error reporting is the Compiler Error. These types of errors are more general than runner errors and may be due to some subtle error in the game code, which cause the it crash while it's Compiling, before it even gets a chance to run. These too will be reported in the Compiler Errors Output Window:
-If the game compiles and an error occurs, you'll get a Runner Error. This type of error will show an onscreen message, much like the one shown below:
-Most runner error messages follow the same outline, with a message stating the type of error, the instance and event in which the error was encountered, then a series of runner details that explain the error in a lot more depth and, finally, a list of all the declared global, instance and local variables in your game at that point. At the very bottom is the Abort button which will abort the game, as well as the Copy button (which copies the error into the clipboard) and the Clear button which clears the error messages from the window. The information provided by the error reporting here is very important as it detects and reports the large, syntax related bugs that are going to cause your finished game to crash, but note that it won't report more subtle bugs, nor does it give feedback on performance... for that you need to use the Debugger.
-The following pages outline all the different Syntax, Runner, and Compiler errors that you can get and what they mean:
+Pierwszą formą zgłaszania błędów jest błąd składni. Jest to błąd w kodzie, który GameMaker wyłapał przed próbą kompilacji i który zostanie wyświetlony na stronie IDE, w edytorze kodu lub w oknie wyjściowym Syntax Errors Output Window:
+Kolejnym poziomem raportowania błędów jestBłąd kompilatora. Tego typu błędy są bardziej ogólne niż błędy runnera i mogą być spowodowane jakimś subtelnym błędem w kodzie gry, który powoduje awarię podczas kompilacji, zanim gra zdąży się uruchomić. Również one zostaną zgłoszone w oknie wyjściowym Błędy kompilatora:
+Jeśli gra skompiluje się i wystąpi błąd, pojawi się Błąd runnera. Ten typ błędu spowoduje wyświetlenie na ekranie komunikatu, podobnego do pokazanego poniżej:
+Większość komunikatów o błędach runnera ma ten sam schemat: komunikat określający typ błędu, instancję i zdarzenie, w którym błąd został napotkany, następnie szereg szczegółów runnera, które dokładniej wyjaśniają błąd, a na końcu listę wszystkich zadeklarowanych zmiennych globalnych, instancyjnych i lokalnych w grze w danym momencie. Na samym dole znajduje się przycisk Przerwij , który przerywa grę, a także przycisk Kopiuj (który kopiuje błąd do schowka) oraz przycisk Wyczyść , który usuwa komunikaty o błędach z okna. Informacje dostarczane przez funkcję raportowania błędów są bardzo ważne, ponieważ wykrywa ona i zgłasza duże błędy związane ze składnią, które mogą spowodować awarię gotowej gry, ale należy pamiętać, że nie zgłasza ona bardziej subtelnych błędów ani nie informuje o wydajności.
+Na kolejnych stronach opisano różne błędy składni, programu uruchamiającego i kompilatora, które mogą wystąpić, oraz ich znaczenie:
-
-
+
+
+
-
The second type of error that can be reported for your game is the compiler error. A compiler error happens when your game encounters some type of error that the syntax checker may not have been able to detect - it's very easy to forget to declare a variable or mistakenly type a string as a real, for example - or when an error is related to how you have set up the compile tools from the Platform Preferences for the target platform. These errors will be caught by GameMaker as the game is being compiled and this information will also be shown in the Compiler Error Output, as shown below:
+Drugim typem błędu, który może być zgłoszony dla Twojej gry jest błąd kompilatora. Błąd kompilatora pojawia się, gdy Twoja gra napotka jakiś rodzaj błędu, którego nie był w stanie wykryć system sprawdzania składni - bardzo łatwo jest zapomnieć o zadeklarowaniu zmiennej lub omyłkowo wpisać string jako real, na przykład - lub gdy błąd jest związany z tym, jak ustawiłeś narzędzia kompilacji z Preferencji Platformy dla platformy docelowej. Błędy te zostaną wychwycone przez GameMakera w trakcie kompilacji gry, a informacja o nich pojawi się również w Compiler Error Output, jak pokazano poniżej:
-NOTE These errors don't usually pop up a window and will simply show "Build Failed" in the compiler output. If a window pops up it's usually a Runner Error, which is explained here.
-The compiler error messages will all follow the same format:
+UWAGA Te błędy zazwyczaj nie wyskakują w oknie i po prostu pokażą "Build Failed" w wyjściu kompilatora. Jeśli pojawi się okno, jest to zwykle błąd biegacza, który jest wyjaśniony tutaj.
+Wszystkie komunikaty o błędach kompilatora będą miały ten sam format:
[object] - [event] - [Line Number]: [error string]
-If the error is found in a script then it will simply be:
+Jeśli błąd zostanie znaleziony w script to po prostu będzie:
[script] - [Line Number]: [error string]
-You can then double-click on any of the compiler error entries to open the given asset at the position flagged as giving the error, and then you can use the information contained within the message to pinpoint exactly where in the object or script the error has occurred. However, sometimes these errors can seem a bit cryptic, so below you can find a complete list of all errors and a brief explanation of what they mean:
-+
Możesz wtedy dwukrotnie kliknąć na dowolnym wpisie błędu kompilatora, aby otworzyć daną asset w miejscu oznaczonym jako dające błąd, a następnie możesz użyć informacji zawartych w komunikacie, aby dokładnie określić, w którym miejscu object lub script wystąpił błąd. Jednak czasami te błędy mogą wydawać się nieco tajemnicze, więc poniżej znajdziesz pełną listę wszystkich błędów i krótkie wyjaśnienie, co one oznaczają:
+
Error | -Description | +Błąd | +Opis |
---|---|---|---|
- Miscellaneous +Różne |
|||
No program to compile | -A previous compile error has caused the compiler parse tree to not be created and thus the compiler has no program data to compile | +Brak programu do kompilacji | +Poprzedni błąd kompilacji spowodował, że drzewo parsowania kompilatora nie zostało utworzone, a więc kompilator nie ma danych programu do kompilacji |
Fatal Error while compiling [name] - bailing details below | -This message simply means that some error has been discovered but the compiler cannot place what or where (if this happens consistently you may wish to contact support and supply the details that the compiler output window shows) | +Ta wiadomość oznacza po prostu, że jakiś błąd został wykryty, ale kompilator nie może określić co i gdzie (jeśli to się dzieje konsekwentnie, możesz chcieć skontaktować się z pomocą techniczną i dostarczyć szczegóły, które pokazuje okno wyjściowe kompilatora) | |
Recursive macro expansion is not supported | -You have used recursive macros that refer to each other and constantly expand | +Rekursywne rozszerzanie makr nie jest obsługiwane | +Użyłeś rekurencyjnych makr, które odwołują się do siebie i stale rozszerzają |
Unable to find TextureGroup [group] | -This error is usually only found from trying to run a malformed project file (if this happens consistently you may wish to contact support and supply the details that the compiler output window shows) | +Nie można znaleźć TextureGroup [group] | +Ten błąd jest zwykle spotykany tylko przy próbie uruchomienia źle sformułowanego pliku projektu (jeśli zdarza się to konsekwentnie, możesz chcieć skontaktować się z pomocą techniczną i dostarczyć szczegóły, które pokazuje okno wyjściowe kompilatora) |
Wrong to convert [value] to number | -You have tried to convert the given value, for example a string, into a number | +Błędna konwersja [value] na liczbę | +Próbowałeś zamienić podaną wartość, np. string, na liczbę |
Division by 0 | -You have tried to divide a value by 0 | +Podział przez 0 | +Próbowałeś podzielić wartość przez 0 |
Invalid object id [object ID] used | -You have tried to access an object using an ID value that is incorrect | +Użyto nieprawidłowego identyfikatora object [object ID] | +Próbowałeś uzyskać dostęp do strony object używając nieprawidłowej wartości ID. |
Unclosed comment (/*) at end of script | -You have created a script comment using - /* [comment] */ - but have not supplied the closing comment tag + | Niezamknięty komentarz (/*) na końcu skryptu | +Utworzyłeś komentarz script używając + /* [comment] */ + ale nie dostarczyłeś zamykającego tagu komentarza |
Invalid token | -You have an invalid character in your game code, which can happen with foreign language characters or Unicode | +Nieważny token | +Masz nieprawidłowy znak w kodzie gry, co może się zdarzyć w przypadku znaków obcojęzycznych lub Unicode |
Number [num] in incorrect format | -The given number - shown in the error - is not the correct format for the function or operation being performed, for example you supply an integer when a pointer is required | +Numer [num] w nieprawidłowym formacie | +Podana liczba - pokazana w błędzie - nie jest prawidłowym formatem dla wykonywanej funkcji lub operacji, np. podajesz liczbę całkowitą, gdy wymagany jest wskaźnik |
Unexpected EOF encountered | -You have reached the end of file unexpectedly while using the File Functions | +Napotkano nieoczekiwane EOF | +Nieoczekiwanie osiągnąłeś koniec pliku podczas korzystania z funkcji plików |
- Strings +Struny |
|||
Unable to Not a string | -You have tried to use "!" (not) on a string | +Nie można Not a string | +Próbowałeś użyć "!" (nie) na ciągu znaków |
Unable to Negate a string | -You have tried to negate a string, for example + | Nie można zanegować ciągu znaków | +Próbowałeś zanegować string, np. string = -string |
- Scripts, Functions and Arguments +Skrypty, Funkcje i argumenty |
|||
Wrong number of arguments for function [function] | -You have supplied too many or too few arguments for the given function | +Niewłaściwa liczba argumentów dla funkcji [function] | +Podałeś zbyt wiele lub zbyt mało argumentów dla danej funkcji |
Failed to parse action_execute_script() - incorrect number of arguments received | -The GML Visual action Execute Script has too many or too few arguments for the given script being called | +Failed to parse action_execute_script() - nieprawidłowa liczba otrzymanych argumentów | +Akcja wizualna GML Execute Script ma zbyt wiele lub zbyt mało argumentów dla wywoływanego script |
Unknown function [function] check to see if script is empty | -A script or function has been called that the compiler does not recognise (this error is usually thrown by empty script asset references since the compiler will strip out these assets on compile) | +Nieznana funkcja [function] sprawdź, czy script jest pusta | +Wywołana została strona script lub funkcja, której kompilator nie rozpoznaje (ten błąd jest zwykle powodowany przez puste odwołania script asset, ponieważ kompilator usuwa te assets podczas kompilacji) |
Function [function] expects n arguments, a provided | -A function has been given the wrong number of arguments (n) when a certain number were expected (a) | +Funkcja [function] oczekuje argumentów n, a dostarczonych | +Funkcja otrzymała niewłaściwą liczbę argumentów (n), gdy oczekiwano określonej liczby (a) |
Assignment of an empty value (function does not return anything?) | -You have tried to assign a return value from a function when that function returns nothing | +Przypisanie pustej wartości (funkcja nic nie zwraca?) | +Próbowałeś przypisać wartość zwrotną z funkcji, gdy ta funkcja nic nie zwraca |
Unable to find function [function] | -You have called an unknown function | +Nie można znaleźć funkcji [function] | +Wywołałeś nieznaną funkcję |
Calling a function that needs an instance and no instance is available | -The function or script being called is for acting on an instance, but at the time of running no instances exist | +Wywołanie funkcji, która wymaga instancji, a żadna instancja nie jest dostępna | +Wywoływana funkcja lub script służy do działania na instancji, ale w momencie jej uruchomienia nie istnieją żadne instancje |
Calling a function that needs an other and no other is available | -You have used the keyword other outside of the Collision Event or outside of a with statement | +Wywołanie funkcji, która potrzebuje innego, a żaden inny nie jest dostępny | +Użyłeś słowa kluczowego other poza wydarzeniem kolizyjnym lub poza wypowiedzią with. |
Argument naming error, n arguments but no reference found to a | -You have given a number of arguments to a script, but fail to reference one of them in the script, for example, your script takes three arguments but you only use arguments n and a | +Błąd nazwy argumentu, n argumenty, ale nie znaleziono odniesienia do a | +Podałeś kilka argumentów do script, ale nie odwołałeś się do jednego z nich w script, na przykład twój script przyjmuje trzy argumenty, ale używasz tylko argumentów n i a |
Cannot compare arguments | -You have tried to compare two different argument types, like a string and a real number | +Nie można porównać argumentów | +Próbowałeś porównać dwa różne typy argumentów, takie jak string i liczba rzeczywista |
Unknown function or script [functions/script] | -The compiler does not recognise the function or script being called | +Nieznana funkcja lub script [functions/script] | +Kompilator nie rozpoznaje wywoływanej funkcji lub script |
Cannot use resource name [resource] as it is not being exported | -You have tried to access a resource that has not been flagged as part of the project for the platform being compiled to | +Nie można użyć nazwy zasobu [resource] , ponieważ nie jest on eksportowany | +Próbowałeś uzyskać dostęp do zasobu, który nie został oznaczony jako część projektu dla platformy, na którą jest kompilowany |
Cannot use function/script name for a variable, using [functions/script] | -You have tried to use either a function name or a script name as a variable, for example: + | Nie można użyć nazwy funkcji/skryptu dla zmiennej, używając [functions/script] | +Próbowałeś użyć nazwy funkcji lub nazwy script jako zmiennej, na przykład: string = "Hello World" |
Cannot use an argument outside a script | -The built in argument variables can only be used inside a script but you have tried to use them elsewhere | +Nie można użyć argumentu poza skryptem | +Wbudowane zmienne argumentów mogą być używane tylko wewnątrz script, ale próbowałeś użyć ich gdzie indziej |
No references to argument[num] but references argument[num] | -You are using a reference to an argument that does not exist but that could map to another argument | +Brak odniesień do argument[num], ale odniesienia argument[num] | +Używasz odniesienia do argumentu, który nie istnieje, ale który mógłby mapować do innego argumentu |
Incorrect number of arguments for accessor | -You have supplied the wrong number of arguments when using an accessor | +Nieprawidłowa liczba argumentów dla accessora | +Podałeś niewłaściwą liczbę argumentów podczas używania akcesora |
Wrong type of arguments for (one of the below): - /, div, mod, +, -, &&, ||, &, |, ^, <<, >> |
- You have supplied the wrong type of argument for the expression being evaluated | +Zły typ argumentów dla (jednego z poniższych): + /, div, mod, +, -, &&, ||, &, ^, <<, >>. |
+ Podałeś niewłaściwy typ argumentu dla ocenianego wyrażenia |
- Variables +Zmienne |
|||
Using uninitialized variable [var] | -You have tried to use the named variable before it has been initialised | +Użycie niezainicjowanej zmiennej [var] | +Próbowałeś użyć nazwanej zmiennej przed jej inicjalizacją |
Variable [var] is read-only | -You have tried to change the named variable when it cannot be changed | +Zmienna [var] jest tylko do odczytu | +Próbowałeś zmienić nazwaną zmienną, gdy nie można jej zmienić |
Unable to find variable named [var] | -The named variable cannot be found in the current compile | +Nie można znaleźć zmiennej o nazwie [var] | +Nazwana zmienna nie może być znaleziona w bieżącej kompilacji |
Malformed variable reference | -You have tried to reference a variable in the wrong way | +Nieprawidłowe odniesienie do zmiennej | +Próbowałeś odwołać się do zmiennej w niewłaściwy sposób |
Trying to set a read only variable [var] | -You have tried to set a variable that is read only | +Próba ustawienia zmiennej tylko do odczytu [var] | +Próbowałeś ustawić zmienną, która jest tylko do odczytu |
Cannot re-declare a built in variable | -You have tried to declare a local variable using the same name as one of the built in variables | +Nie można ponownie zadeklarować zmiennej wbudowanej | +Próbowałeś zadeklarować zmienną lokalną używając tej samej nazwy co jedna z wbudowanych zmiennych |
Cannot use resource name for a variable | -You have use the same name as a resource from the resource tree as a local variable | +Nie można użyć nazwy zasobu dla zmiennej | +Możesz użyć tej samej nazwy co zasób z drzewa zasobów jako zmiennej lokalnej |
[Variable] is read-only | -You have tried to use a variable that has been flagged as read only | +[Zmienna] jest tylko do odczytu | +Próbowałeś użyć zmiennej, która została oznaczona jako tylko do odczytu |
- Constants +Stałe |
|||
Cannot set a constant [constant] to a value | -You have tried to set a constant to a different value | +Nie można ustawić na wartość stałej [constant] | +Próbowałeś ustawić stałą na inną wartość |
Constant is invalid here | -You have tried to use a constant somewhere that is not valid for the code being run | +Stała jest tu nieważna | +Próbowałeś użyć gdzieś stałej, która nie jest ważna dla uruchamianego kodu |
Cannot assign to [var] - it's a constant | -You have tried to assign a new value to the named constant | +Nie można przypisać do [var] - jest to stała | +Próbowałeś przypisać nową wartość do nazwanej stałej |
- Arrays +Tablice |
|||
Array index should not be negative | -You have tried to access, create, or set an array value using a negative array index | +Indeks tablicy nie powinien być ujemny | +Próbowałeś uzyskać dostęp, utworzyć lub ustawić wartość tablicy przy użyciu ujemnego indeksu tablicy |
- Malformed... +Malformacja... |
|||
Malformed Conditional operator | -You have used an erroneous conditional (ternary) operator or if statement, and not the format: + | Nieprawidłowo sformułowany operator warunkowy | +Użyłeś błędnego operatora warunkowego (trójskładnikowego) lub if statement, a nie formatu: [condition] ? [expression1] : [expression2]; |
If requires a then statement | -You have written an if statement and expression to evaluate, but not given any then part to run | +Jeśli wymaga oświadczenia then | +Napisałeś if statement i wyrażenie do oceny, ale nie podałeś żadnej części do uruchomienia |
malformed assignment statement | -In the code you are using an assignment operator wrong | +nieprawidłowo sformułowane oświadczenie o przypisaniu | +W kodzie używasz operatora przypisania błędnie |
Malformed - if / repeat / while / do / for / with / switch / break / continue / exit - statement |
- The structure of the given statement is incorrect. | +Zniekształcona + if / repeat / while / do / for / with / switch / break / continue / exit + oświadczenie |
+ Struktura podanej wypowiedzi jest nieprawidłowa. |
Malformed post inc or dec statement | -You have tried to use [var]++ or [var]-- in an illegal way | +Nieprawidłowe oświadczenie post inc lub dec | +Próbowałeś używać [var]++ lub [var]-- w sposób nielegalny. |
Malformed pre inc or dec statement | -You have tried to use ++[var] or --[var] in an illegal way | +Nieprawidłowo sformułowana deklaracja pre inc lub dec | +Próbowałeś używać ++[var] lub --[var] w sposób nielegalny. |
Malformed global gml_pragma | -You have created a wrong global string when using gml_pragma | +Niewłaściwa globalna gml_pragma | +Stworzyłeś błędny globalny string podczas używania gml_pragma |
Malformed PNGCrush gml_pragma | -You have created a wrong string command for PNGCrush when using gml_pragma | +Nieformalny PNGCrush gml_pragma | +Stworzyłeś złe polecenie string dla PNGCrush podczas używania gml_pragma |
Malformed Texgroup.Scale gml_pragma | -You have create a wrong global string when using gml_pragma | +Złe sformułowanie Texgroup.Scale gml_pragma | +Stworzyłeś błędny globalny string podczas używania gml_pragma |
@@ -291,87 +291,87 @@ Compile Errors |
|||
Default cannot be used multiple times in a switch | -In your switch statement you have defined default: more than once | +Default nie może być używany wielokrotnie w przełączniku | +W twoim oświadczeniu switch zdefiniowałeś domyślne: więcej niż raz |
Clause expression type mismatch (clause expressions should all be the same type) | -In your switch you are checking for two different constant case types, for example a string in one case and an integer in another | +Niedopasowanie typu wyrażenia klauzuli (wszystkie wyrażenia klauzuli powinny być tego samego typu) | +W twoim switch sprawdzasz dla dwóch różnych stałych typów przypadków, na przykład string w jednym przypadku i liczba całkowita w innym |
Case argument should be a constant | -You have tried to use a value that does not evaluate to a constant within one of your switch cases | +Argumentacja w sprawie powinna być stała | +Próbowałeś użyć wartości, która nie jest stała w jednym z twoich przypadków switch |
Statement in a switch MUST appear after case or default | -You have added a statement to a switch outside of either a case: or default: call | +Oświadczenie na stronie switch MUSI pojawić się po literze "case" lub "default". | +Dodałeś deklarację do switch poza wywołaniem case: lub default: |
Duplicate case statement found / original here | -You have used the same case constant in two different places within a switch (note that the "original here" comment will be on another line and can be clicked to show the original case) | +Znaleziono duplikat oświadczenia w sprawie / oryginał tutaj | +Użyłeś tej samej stałej przypadku w dwóch różnych miejscach w ramach switch (zauważ, że komentarz "oryginalny tutaj" będzie w innej linii i może być kliknięty, aby pokazać oryginalny przypadek.) |
- Expressions +Wyrażenia |
|||
No return value from expression (does expression have a return value?) | -You have tried to assign a return value from an expression to a variable when the expression returns nothing | +Brak wartości zwrotnej z wyrażenia (czy wyrażenie ma wartość zwrotną?) | +Próbowałeś przypisać wartość zwracaną z wyrażenia do zmiennej, gdy wyrażenie nic nie zwraca |
Expecting expression after the '.' | -You have used the point "." notation erroneously and not added an expression afterwords correctly | +Oczekiwanie wyrażenia po ". | +Błędnie użyłeś notacji punktowej "." i nie dodałeś poprawnie wyrażenia po słowach |
Unexpected symbol [symbol] in expression | -The expression uses a symbol that is not part of the accepted expression symbol set - the symbol in question will be shown | +Nieoczekiwany symbol [symbol] w wyrażeniu | +W wyrażeniu użyto symbolu, który nie jest częścią akceptowanego zestawu symboli wyrażenia - symbol ten zostanie pokazany |
- Unknown Operators +Nieznani operatorzy |
|||
Unknown Pre operator | -You have tried to use a symbol as a pre-operator when that symbol is not permitted, for example **[var] or >>[var] - only ++ and -- are acceptable | +Nieznany operator wstępny | +Próbowałeś użyć symbolu jako preoperatora, gdy ten symbol jest niedozwolony, na przykład **[var] lub >>[var] - dopuszczalne są tylko ++ i -- |
Unknown Post operator | -You have tried to use a symbol as a post-operator when that symbol is not permitted, for example [var]** or [var]>> - only ++ and -- are acceptable | +Nieznany operator poczty | +Próbowałeś użyć symbolu jako post-operatora, gdy ten symbol jest niedozwolony, na przykład [var]** lub [var]>> - dopuszczalne są tylko ++ i -- |
Unknown pragma [gml_pragma string] | -You have used a pragma string that is unknown to the compiler | +Nieznana pragma [gml_pragma string] | +Użyłeś pragmy string, która nie jest znana kompilatorowi |
Unknown unary operator | -You have tried to use an unknown symbol as a unary operator | +Nieznany operator jednoargumentowy | +Próbowałeś użyć nieznanego symbolu jako operatora jednoargumentowego |
Unknown binary operator | -You have tried to use an unknown symbol as a binary operator | +Nieznany operator binarny | +Próbowałeś użyć nieznanego symbolu jako operatora binarnego |
Unknown operator [operator] | -You have tried to use an unknown symbol as an operator (the symbol will be shown in the error) | +Nieznany operator [operator] | +Próbowałeś użyć nieznanego symbolu jako operatora (symbol będzie pokazany w błędzie) |
- Break / Continue +Przerwa / Kontynuacja |
|||
Break used without context | -You have not used break within a switch or a loop or any other permitted structure | +Przerwa użyta bez kontekstu | +Nie użyłeś break w ramach switch lub loop lub innej dozwolonej struktury |
Continue used without context | -You have not used continue within the correct context | +Kontynuacja użyta bez kontekstu | +Nie użyłeś continue w odpowiednim kontekście |
continue statement is not allowed at this point | -You have used continue within a apart of your code where it is not permitted | +kontynuowanie wypowiedzi nie jest w tym momencie dozwolone | +Użyłeś continue w części swojego kodu, gdzie jest to niedozwolone |
@@ -379,67 +379,67 @@ Compile Errors |
|||
enum num is invalid | -The enum number is invalid for the enum | +enum num jest niepoprawne | +Numer enum jest nieprawidłowy dla enum |
malformed enum | -You have not created the enum correctly | +zniekształcony enum | +Nie utworzyłeś poprawnie enum |
enum [enum] has already been defined | -You have tried to define an enum using the same name as another previously defined | +enum [enum] zostało już zdefiniowane | +Próbowałeś zdefiniować enum używając tej samej nazwy, co inne wcześniej zdefiniowane |
malformed enum entry | -The enum has an invalid entry | +nieprawidłowy wpis enum | +Liczba ma niepoprawny wpis |
enum expression must be an integer constant | -The enum entry does not evaluate as an integer constant | +wyrażenie enum musi być stałą całkowitą | +Wpis enum nie jest obliczany jako stała całkowita. |
enum reference [key] does not exist in [enum] | -You have tried to reference an enum entry using a key that has not previously been defined for that enum | +Odwołanie do enum [key] nie istnieje w [enum] | +Próbowałeś odwołać się do wpisu enum używając klucza, który nie został wcześniej zdefiniowany dla tego enum |
- Expected Symbols / Values +Oczekiwane symbole / wartości |
|||
Symbol ( expected - Symbol ) expected - Symbol , or ) expected - Symbol { expected - Symbol } expected - Symbol , or } expected - Symbol : expected - Symbol ; expected - Symbol [ expected - symbol ] expected - Symbol , or ] expected |
- You have not used a required symbol when writing your code | +Symbol ( oczekiwany + Symbol ) oczekiwany + Symbol , lub ) oczekiwany + Symbol { oczekiwany + Symbol } oczekiwany + Symbol , lub } oczekiwany + Symbol : oczekiwany + Symbol ; oczekiwany + Symbol [ oczekiwany + symbol ] oczekiwany + Symbol , lub ] oczekiwany |
+ Nie użyłeś wymaganego symbolu podczas pisania swojego kodu |
Expected id or string | -You have used a value that is not either a layer ID or a layer name - as a string - in one of the Layer functions | +Oczekiwane id lub ciąg znaków | +W jednej z funkcji warstwy użyłeś wartości, która nie jest ani identyfikatorem warstwy, ani nazwą warstwy - jako string. |
keyword Until expected | -You have created a do... until loop but neglected to supply an until expression | +słowo kluczowe Do czasu, gdy spodziewano się | +Stworzyłeś do... until loop ale zaniedbałeś dostarczenie wyrażenia until |
Function name expected | -You have used something other than a function name in your code where a function should go | +Oczekiwana nazwa funkcji | +Użyłeś czegoś innego niż nazwa funkcji w swoim kodzie, gdzie powinna być funkcja |
variable name expected | -You have supplied a name that is not a variable name where one is expected | +oczekiwana nazwa zmiennej | +Podałeś nazwę, która nie jest nazwą zmiennej tam, gdzie jest ona oczekiwana |
Assignment operator expected | -You have created an assignment which expects an operator but none has been supplied | +Oczekiwany operator przypisania | +Utworzyłeś zadanie, które oczekuje operatora, ale żaden nie został dostarczony |
@@ -447,20 +447,20 @@ Compile Errors |
|||
Android ARM ToolChain directory [dir] does not exist | -The link given in the Android Preferences for the ARM toolchain is incorrect and does not exist. | +Android ARM Nie istnieje katalog ToolChain [dir] | +Link podany w Android Preferences dla ARM toolchain jest nieprawidłowy i nie istnieje. |
Android MIPS ToolChain directory [dir] does not exist | -The link given in the Android Preferences for the MIPS toolchain is incorrect and does not exist. | +Nie istnieje katalog Android MIPS ToolChain [dir] | +Link podany w Android Preferences dla MIPS toolchain jest nieprawidłowy i nie istnieje. |
Android x86 ToolChain directory [dir] does not exist | -The link given in the Android Preferences for the x86 toolchain is incorrect and does not exist. | +Nie istnieje katalog Android x86 ToolChain [dir] | +Link podany w Android Preferences dla toolchaina x86 jest nieprawidłowy i nie istnieje. |
Android NDK directory [dir] does not exist | -The link given in the Android Preferences for the Android NDK is incorrect and does not exist. | +Katalog Android NDK [dir] nie istnieje | +Link podany w Preferencjach Android dla Android NDK jest nieprawidłowy i nie istnieje. |
@@ -468,22 +468,22 @@ Compile Errors |
|||
Configuration Problem : Windows Visual Studio Path needs to be set to point to Visual Studio (.bat) batch file. | -The link given in the Windows Preferences for the Visual Studio (.bat) batch file is incorrect and does not exist. | +Problem konfiguracyjny : Windows Visual Studio Path musi być ustawiony tak, aby wskazywał na plik wsadowy Visual Studio (.bat). | +Link podany w Preferencjach Windows dla pliku wsadowego Visual Studio (.bat) jest nieprawidłowy i nie istnieje. |
-
-
+
+
+
-
Even after syntax checking in the code editor and then having the compiler check your code for compiler errors, there are still occasions when something can go wrong. In most cases this will throw a Virtual Machine (VM) runner error (also called a runtime exception) which looks like this:
- -Runner errors are generally more serious than compile errors as it means that there is something seriously wrong with your code that neither the code editor nor the compiler have been able to detect, and as such you should pay attention to all such errors. When one occurs, you can use the Copy button on the pop-up to copy the error to the clipboard which you can then paste into a text file (or wherever) for future reference.
-The structure of this error is as follows:
+Nawet po sprawdzeniu składni w edytorze kodu, a następnie sprawdzeniu kodu pod kątem błędów przez kompilator, nadal zdarzają się sytuacje, w których coś może pójść nie tak. W większości przypadków spowoduje to wyświetlenie błędu runnera maszyny wirtualnej (zwanego również wyjątkiem runtime), który wygląda tak:
+Błędy uruchamiania są na ogół poważniejsze niż błędy kompilacji, ponieważ oznaczają, że w kodzie jest coś poważnego, czego nie udało się wykryć ani edytorowi kodu, ani kompilatorowi, dlatego należy zwracać uwagę na wszystkie takie błędy. W przypadku wystąpienia takiego błędu można użyć przycisku Kopiuj w wyskakującym okienku, aby skopiować błąd do schowka, który można następnie wkleić do pliku tekstowego (lub gdziekolwiek indziej) w celu wykorzystania w przyszłości.
+Struktura tego błędu jest następująca:
As mentioned above, certain error messages will be identify the scope not by an instance ID value, but rather by a negative value. These values can be used to pinpoint the exact nature of the error and what it refers to with the following values possible:
+Jak wspomniano powyżej, niektóre komunikaty o błędach będą identyfikować zakres nie za pomocą wartości ID instancji, ale raczej za pomocą wartości ujemnej . Wartości te można wykorzystać do dokładnego określenia natury błędu oraz tego, do czego się odnosi, korzystając z następujących możliwych wartości:
Prefix | -Scope | +Prefiks | +Zakres |
---|---|---|---|
-1 | @@ -42,11 +39,11 @@|||
-2 | -Other | +Inne | |
-3 | -All | +Wszystkie | |
-4 | @@ -58,47 +55,35 @@|||
-6 | -Not Specified | +Nie określono. | |
-7 | -Local | +Lokalna strona |
-
The possible errors from the VM runner are as follows:
++
Możliwe błędy występujące w VM runnerze są następujące:
Error | -Message | -Operation | -Description | +Błąd | +Wiadomość | +Operacja | +Opis |
---|---|---|---|---|---|---|---|
DoSet | -Invalid comparison type | -Data Types | -This denotes that the runner has tried to compare two incompatible data types, like a real number with a string. | +Nieprawidłowy typ porównania | +Typy danych | +Oznacza to, że biegacz próbował porównać dwa niekompatybilne typy danych, np. liczbę rzeczywistą z liczbą string. | |
DoConv | -Execution Error | -Data Types | -This denotes an error in the conversion of one data-type into another. | -||||
Argument Type | -(function) argument (index) incorrect type (wrong_type) expecting a (expected_type) | -Data Types | -A value with the wrong data type was passed as an argument to the function at (index) (where an index of 1 is the first argument). A value of wrong_type was given but it should be one of expected_type instead. | +Błąd wykonania | +Typy danych | +Oznacza to błąd w konwersji jednego typu danych na inny. | |
@@ -107,57 +92,57 @@ Runner Errors | |||||||
DoAdd | -Execution Error | -Maths | -Something has gone wrong when using the addition (+) expression. | +Błąd wykonania | +Matematyka | +Coś poszło nie tak podczas używania wyrażenia dodawania (+). | |
DoMul | -Execution Error | -Maths | -Something has gone wrong when using the multiplication (*) expression. | +Błąd wykonania | +Matematyka | +Coś poszło nie tak podczas używania wyrażenia mnożenia (*). | |
DoSub | -Execution Error | -Maths | -Something has gone wrong when using the subtraction (-) expression. | +Błąd wykonania | +Matematyka | +Coś poszło nie tak podczas używania wyrażenia odejmowania (-). | |
DoSub | -Execution Engine - Cannot operate on string type | -Maths | -You are trying to subtract the wrong type of variables (for example subtract a string from a real). | +Silnik wykonawczy - nie można operować na typie string | +Matematyka | +Próbujesz odejmować zmienne niewłaściwego typu (np. odjąć string od rzeczywistej). | |
DoDiv | -Execution Error | -Maths | -Something has gone wrong when using the division (/ or div) expression. | +Błąd wykonania | +Matematyka | +Coś poszło nie tak podczas używania wyrażenia dzielenia (/ lub div). | |
DoDiv | -Execution Engine - Cannot operate on string type | -Maths | -You are trying to divide the wrong type of variables (for example divide a string by a real). | +Silnik wykonawczy - nie można operować na typie string | +Matematyka | +Próbujesz dzielić zmienne niewłaściwego typu (np. dzielić string przez rzeczywistą). | |
DoDiv | -Divide by zero | -Maths | -You are attempting to divide by 0 (note this will only happen when using integer division, dividing a (non-zero) real by 0 will give infinity as an answer, dividing zero by zero will give NaN as an answer). You can check for these values with (is_infinity) and (is_nan) | +Podzielić przez zero | +Matematyka | +Próbujesz podzielić przez 0 (zauważ, że dzieje się tak tylko wtedy, gdy używasz dzielenia przez liczby całkowite, dzielenie (niezerowej) liczby rzeczywistej przez 0 da w wyniku nieskończoność, a dzielenie zera przez zero da w wyniku NaN). Można sprawdzić te wartości za pomocą (is_infinity) i (is_nan) | |
DoMod | -Execution Error | -Maths | -Something has gone wrong when using the modulo (mod) expression. | +Błąd wykonania | +Matematyka | +Coś poszło nie tak podczas używania wyrażenia modulo (mod). | |
DoMod | -Execution Engine - Cannot operate on string type | -Maths | -You are trying to use modulo (mod) on the wrong type of variables (for example mod a string by a real). | +Silnik wykonawczy - nie można operować na typie string | +Matematyka | +Próbujesz użyć funkcji modulo (mod) na zmiennych niewłaściwego typu (na przykład mod a string przez rzeczywistą). | |
@@ -166,63 +151,63 @@ Runner Errors | |||||||
DoAnd | -Execution Error | +Błąd wykonania | Bitwise | -Something has gone wrong when using the bitwise "and" (&) expression. | +Coś poszło nie tak podczas używania wyrażenia bitowego "i" (&). | ||
DoAnd | -Execution Engine - Cannot operate on string type | +Silnik wykonawczy - nie można operować na typie string | Bitwise | -You are trying to use bitwise "and" (&) on the wrong type of variables (for example trying to "and" a string with a real). | +Próbujesz użyć bitowego "i" (&) na zmiennych niewłaściwego typu (na przykład próbujesz "i" string z liczbą rzeczywistą). | ||
DoOr | -Execution Error | +Błąd wykonania | Bitwise | -Something has gone wrong when using the bitwise "or" (|) expression. | +Coś poszło nie tak podczas używania wyrażenia bitowego "lub" (|). | ||
DoOr | -Execution Engine - Cannot operate on string type | +Silnik wykonawczy - nie można operować na typie string | Bitwise | -You are trying to use "or" (|) on the wrong type of variables (for example trying to "or" a string with a real). | +Próbujesz użyć "lub" (|) na zmiennych niewłaściwego typu (na przykład próbujesz "lub" string z real). | ||
DoXor | -Execution Error | +Błąd wykonania | Bitwise | -Something has gone wrong when using the bitwise "xor" (^) expression. | +Coś poszło nie tak podczas używania wyrażenia bitowego "xor" (^). | ||
DoXor | -Execution Engine - Cannot operate on string type | +Silnik wykonawczy - nie można operować na typie string | Bitwise | -You are trying to use "xor" (^) on the wrong type of variables (for example trying to "xor" a string with a real). | +Próbujesz użyć funkcji "xor" (^) na zmiennych niewłaściwego typu (na przykład próbujesz "xorować" zmienną string z rzeczywistą). | ||
DoShl | -Execution Error | +Błąd wykonania | Bitwise | -Something has gone wrong when bitshifting left (<<) a value. | +Coś poszło nie tak podczas przesuwania bitów w lewo (<<) wartości. | ||
DoShl | -Execution Engine - Cannot operate on string type | +Silnik wykonawczy - nie można operować na typie string | Bitwise | -You are trying to left bitshift (<<) the wrong type of variables (for example trying to bitshift a string). | +Próbujesz przesunąć w lewo (<<) zmienne niewłaściwego typu (na przykład próbujesz przesunąć w lewo zmienną string). | ||
DoShr | -Execution Error | +Błąd wykonania | Bitwise | -Something has gone wrong when bitshifting right (>>) a value. | +Coś poszło nie tak podczas przesuwania bitów w prawo (>>) wartości. | ||
DoShr | -Execution Engine - Cannot operate on string type | +Silnik wykonawczy - nie można operować na typie string | Bitwise | -You are trying to right bitshift (>>) the wrong type of variables (for example trying to bitshift a string). | +Próbujesz przesunąć w prawo (>>) zmienne niewłaściwego typu (na przykład próbujesz przesunąć w prawo zmienną string). | ||
@@ -231,15 +216,15 @@ Runner Errors | |||||||
DoNeg | -Execution Error | -Negate | -You are trying to turn a variable type into a negative when this type does not permit such an operation. | +Błąd wykonania | +Neguj | +Próbujesz zamienić zmienną typu na ujemną, gdy ten typ nie pozwala na taką operację. | |
DoNot | -Execution Error | -Negate | -You are trying to "not" a variable type when this type does not permit such an operation. | +Błąd wykonania | +Neguj | +Próbujesz "nie" typu zmiennej, gdy ten typ nie pozwala na taką operację. | |
@@ -248,27 +233,27 @@ Runner Errors | |||||||
Push | -Execution Error - Variable Index out of range (var) | -Stack | -The variable being accessed is out with the established range for the runner. | +Błąd wykonania - Indeks zmiennej poza zakresem (var) | +Stos | +Zmienna, do której uzyskuje się dostęp, znajduje się poza ustalonym zakresem dla biegacza. | |
Push | -Variable Get (var) | -Stack | -The given variable has not been defined or is unknown. | +Zmienna Uzyskaj (var) | +Stos | +Podana zmienna nie została zdefiniowana lub jest nieznana. | |
Pop | -Variable Index out of range (var) | -Stack | -The variable being accessed is out with the established range for the runner. | +Zmienna Indeks poza zakresem (var) | +Stos | +Zmienna, do której uzyskuje się dostęp, znajduje się poza ustalonym zakresem dla biegacza. | |
Pop | -Variable Get (var) | -Stack | -The given variable has not been defined or is unknown. | +Zmienna Uzyskaj (var) | +Stos | +Podana zmienna nie została zdefiniowana lub jest nieznana. | |
@@ -277,9 +262,9 @@ Runner Errors | |||||||
With | -Cannot use global in with statement | -With | -You have tried to use "global" as a variable within a "with" statement, ie: + | Nie można użyć wartości globalnej w wyrażeniu with | +Z | +Próbowałeś użyć "global" jako zmiennej w oświadczeniu "with", tzn: with (global) { //do something; @@ -288,9 +273,9 @@ Runner Errors | |
With | -Cannot use local in with statement | -With | -You have tried to use "local" as a variable within a "with" statement, ie: + | Nie można użyć local w wyrażeniu with | +Z | +Próbowałeś użyć "local" jako zmiennej w oświadczeniu "with", tzn: with (local) { //do something; @@ -304,44 +289,32 @@ Runner Errors | |
DoCall | -Execution Engine type error | -Engine | -This is an undefined error within the Virtual Machine. You should file a bug report should this happen (see: The Help Menu for details on how to do this. | +Błąd typu silnika wykonawczego | +Silnik | +Jest to błąd undefined występujący w maszynie wirtualnej. W takim przypadku należy zgłosić błąd (szczegółowe informacje na ten temat znajdują się w: Menu Pomoc. | |
Stack Overflow | - | -Engine | -A stack overflow occurs when too much memory is used on the call stack and when your game attempts to use more space than is available on the call stack (that is, when it attempts to access memory beyond the call stack's bounds, which is essentially a buffer overflow), the stack is said to overflow, resulting in a program crash. Restart your computer and GameMaker and if the error persists please get in touch with support and/or file a bug (as explained above). | -||||
- - |
- |||||||
Read Variable | -Variable not set before reading it | -Variable Initialisation | -You are trying to access a variable that hasn't been set (i.e. initialised) yet. Assign a value to it first before trying to read it, e.g. variable = 100;. Only declaring a variable, using e.g. var variable; will also throw this error. | +Silnik | +Przepełnienie stosu ma miejsce, gdy na stosie wywołań znajduje się zbyt dużo pamięci i gdy Twoja gra próbuje wykorzystać więcej miejsca, niż jest dostępne na stosie wywołań (to znaczy, gdy próbuje uzyskać dostęp do pamięci poza granicami stosu wywołań, co jest zasadniczo przepełnieniem buffer ), mówi się, że stos się przepełnia, co powoduje awarię programu. Uruchom ponownie komputer i GameMakera, a jeśli błąd będzie się powtarzał, skontaktuj się z działem pomocy technicznej i/lub zgłoś błąd (jak opisano powyżej). |
-
-
+
+
+
-
The first level of error reporting when programming your games in GameMaker is in the code or GML Visual editor, and it's the syntax checker. As you write your code - or add your actions - GameMaker will check that it follows the established syntax for the language, and flag any issues that it finds so you can fix them before it comes to running the game or compiling an executable.
-Syntax error checking happens differently depending on whether you have enabled Feather in the Feather Settings.
-Pierwszy poziom raportowania błędów podczas programowania gier w GameMakerze znajduje się w edytorze kodu lub GML Visual, a jest nim sprawdzanie składni. Gdy piszesz swój kod - lub dodajesz swoje akcje - GameMaker sprawdza, czy jest on zgodny z ustaloną składnią dla danego języka i flag wszelkie problemy, które znajdzie, abyś mógł je naprawić zanim dojdzie do uruchomienia gry lub kompilacji pliku wykonawczego.
+Sprawdzanie błędów składniowych przebiega inaczej w zależności od tego, czy włączyłeś Feather w Ustawieniach Feather.
+These errors fall into two main categories:
+Błędy te dzielą się na dwie główne kategorie:
Syntax errors will update as you write your code (there will be a short pause between typing something and any errors appearing in this window to prevent errors being reported for unfinished code), and will follow the format:
+Błędy składniowe będą aktualizowane w miarę pisania kodu (pomiędzy wpisaniem czegoś a pojawieniem się błędów w tym oknie będzie krótka przerwa, aby zapobiec zgłaszaniu błędów dla niedokończonego kodu), i będą zgodne z formatem:
[object] - [event] - [Line Number] - [Position In Line]: [error string]
-Or if the error is in a script, it will be:
+Albo jeśli błąd jest w script, to będzie:
[script] - [Line Number] - [Position in line]: [error string]
-Double clicking on any of the errors shown in the output console will take you to the line in the object event or script that has the error so you can edit it.
-It should be noted that some of these errors will be shown at specific places in your code, but the actual error may be cause by something elsewhere, or one single issue may provoke multiple error messages:
-In the above image, all three errors have been provoked by a single mistake - the use of a semi colon ";" instead of a comma "," at line 220 for the function variable_instance_exists().
-The table below lists the different syntax errors and their main causes:
-+
Podwójne kliknięcie na którymkolwiek z błędów pokazanych w konsoli wyjściowej przeniesie cię do linii w zdarzeniu object lub script, która ma błąd, więc możesz ją edytować.
+Należy zauważyć, że niektóre z tych błędów będą wyświetlane w określonych miejscach w twoim kodzie, ale rzeczywisty błąd może być spowodowany przez coś innego, lub jeden problem może wywołać wiele komunikatów o błędach:
+Na powyższym obrazku wszystkie trzy błędy zostały sprowokowane przez jeden błąd - użycie średnika ";" zamiast przecinka "," w linii 220 dla funkcji variable_instance_exists().
+Poniższa tabela zawiera listę różnych błędów składni i ich głównych przyczyn:
+
Error | -Type | -Description | +Błąd | +Typ | +Opis |
---|---|---|---|---|---|
Malformed reference [val] | -- | This means there is an internal AST Validation Error (you should never see this error, but if you do please consider filing a bug report from the Help Menu) | ++ | Oznacza to, że wystąpił wewnętrzny błąd walidacji AST (nie powinieneś nigdy zobaczyć tego błędu, ale jeśli tak się stanie, rozważ zgłoszenie błędu z menu Pomoc) | |
Malformed hexadecimal character escape sequence | +Niewłaściwa sekwencja ucieczki znaków szesnastkowych | - | This can happen when you have used the hexadecimal value for an escape character in a string and this has the wrong format. | +Może się to zdarzyć, gdy użyłeś wartości szesnastkowej dla znaku ucieczki w string i ma to niewłaściwy format. | |
Unexpected node [val] | -- | This means there is an internal AST Validation Error (you should never see this error, but if you do please consider filing a bug report from the Help Menu) | +Nieoczekiwany węzeł [val] | ++ | Oznacza to, że wystąpił wewnętrzny błąd walidacji AST (nie powinieneś nigdy zobaczyć tego błędu, ale jeśli tak się stanie, rozważ zgłoszenie błędu z menu Pomoc) |
Exception while parsing [val] | -- | This means there is an internal AST Validation Error (you should never see this error, but if you do please consider filing a bug report from the Help Menu) | +Wyjątek podczas parsowania [val] | ++ | Oznacza to, że wystąpił wewnętrzny błąd walidacji AST (nie powinieneś nigdy zobaczyć tego błędu, ale jeśli tak się stanie, rozważ zgłoszenie błędu z menu Pomoc) |
Malformed id reference [val] | - | + | |||
Unnecessary expression [val] used as a statement | +Niepotrzebne wyrażenie [val] użyte jako stwierdzenie | - | This error occurs when the syntax checker detects an expression (shown in [val]) where it was expecting a statement. For example, the following code will throw the error as it's expecting the ternary operator ? but encounters 32: + | Ten błąd pojawia się, gdy sprawdzacz składni wykryje wyrażenie (pokazane w [val]), gdzie spodziewał się oświadczenia. Na przykład, następujący kod rzuci błąd, ponieważ oczekuje operatora trójskładnikowego ? ale napotyka 32: temp_x = x < (room_width / 2) 32: room_width - 32; |
|
Malformed array reference [val] | - | This means you have tried to reference an array in an incorrect way, and [val] will show the reference. | +Oznacza to, że próbowałeś odwołać się do tablicy w nieprawidłowy sposób, a [val] pokaże to odniesienie. | ||
Unexpected binary operator [val] | +Nieoczekiwany operator binarny [val] | - | This error occurs when you use one of the bitwise operators in a place where it shouldn't be getting used, with [val] showing where. | +Ten błąd występuje, gdy używasz jednego z operatorów bitowych w miejscu, w którym nie powinien być używany, z [val] pokazując, gdzie. | |
Unterminated string literal | +Nie zakończone string dosłowne | - | This error will occur when you open a string using @“ or “ but you do not close it before the end of code. | +Ten błąd pojawi się, gdy otworzysz stronę string za pomocą @“ lub “, ale nie zamkniesz jej przed końcem kodu. | |
Single quotes no longer allowed for string | +Pojedyncze cudzysłowy nie są już dozwolone dla łańcuchów | - | This error occurs when you try to use strings wrapped in single quotes, eg: 'Hello World', instead of double quotes, eg: "Hello World". | +Ten błąd pojawia się, gdy próbujesz użyć strings zawiniętego w pojedyncze cudzysłowy, np. "Hello World", zamiast podwójnych cudzysłowów, np. | |
Unexpected syntax error | +Nieoczekiwany błąd składni | - | This error denotes a syntax error which the parser is not able to identify more specifically. | +Ten błąd oznacza błąd składni, którego parser nie jest w stanie dokładniej zidentyfikować. | |
Got "[val1]", expected "[val2]" | +Otrzymano "[val1]", oczekiwano "[val2]" | - | This happens when the syntax checker expects some value or symbol but gets a different one, where [val1] is the current symbol or value, and [val2] is the expected symbol or value. For example: + | Dzieje się tak, gdy sprawdzacz składni oczekuje jakiejś wartości lub symbolu, ale dostaje inną, gdzie [val1] jest bieżącym symbolem lub wartością, a [val2] jest oczekiwanym symbolem lub wartością. Na przykład: Got "{", expected "(" |
|
Got "[val1]", expected "[val2]" or "[val3]" | +Otrzymano "[val1]", oczekiwano "[val2]" lub "[val3]" | - | As above, but for when there are multiple possible expected symbols. | +Jak wyżej, ale dla sytuacji, gdy istnieje wiele możliwych oczekiwanych symboli. | |
Expected expression | +Oczekiwane wyrażenie | - | This error occurs when the syntax checker expects an expression but one isn't given. | +Ten błąd pojawia się, gdy sprawdzanie składni oczekuje wyrażenia, ale nie zostało ono podane. | |
Empty [val] statement | +Puste oświadczenie [val] | - | This happens when you terminate a statement and leave it empty. For example, the following code will give the error (note the terminating semi-colon): + | Dzieje się tak, gdy kończysz oświadczenie i pozostawiasz je puste. Na przykład następujący kod da błąd (zwróć uwagę na kończący średnik): if (x < 0); |
|
Nested function calls are not allowed | +Zagnieżdżone wywołania funkcji nie są dozwolone | - | This can happen when you are trying to nest function calls within a statement, eg: + | Może się to zdarzyć, gdy próbujesz zagnieżdżać wywołania funkcji w ramach oświadczenia, np: ds_list_find_value(list, 0)).sprite_index |
|
Number of arguments for function [val1] expected [val2] got val[3] | +Liczba argumentów dla funkcji [val1] oczekiwana [val2] got val[3] | - | This error tells you that you have not supplied the correct number of arguments to the function shown for [val1], which expects the number shown in [val2] but got those shown in [val3]. | +Ten błąd mówi Ci, że nie podałeś prawidłowej liczby argumentów do funkcji pokazanej dla [val1], która oczekuje liczby pokazanej w [val2], ale dostała te pokazane w [val3]. | |
Number of arguments for function [val1] expected [val2] - [val3] got [val4] | +Liczba argumentów dla funkcji [val1] oczekiwana [val2] - [val3] otrzymana [val4] | - | As above only for a range of arguments. | +Jak wyżej tylko dla zakresu argumentów. | |
Duplicate enum entry found | +Znaleziono duplikat wpisu enum | - | This error tells you that you have duplicated an enum variable entry name | +Ten błąd informuje, że powielono nazwę wpisu zmiennej enum | |
Duplicate enum found | +Znaleziono duplikat enum | - | This error tells you that you have defined two or more enums with the same name. | +Ten błąd informuje, że zdefiniowałeś dwa lub więcej enum o tej samej nazwie. | |
Missing variable name in globalvar | +Brakująca nazwa zmiennej w globalvar | - | This tells you that you have used the globalvar declaration but omitted to supply a variable name. | +To mówi ci, że użyłeś deklaracji globalvar, ale pominąłeś dostarczenie nazwy zmiennej. | |
Missing variable name in var | +Brakująca nazwa zmiennej w var | - | This tells you that you have used the var declaration but omitted to supply a variable name. | +To mówi ci, że użyłeś deklaracji var, ale pominąłeś dostarczenie nazwy zmiennej. | |
No matching #region found for #endregion | +Nie znaleziono pasującego #regionu dla #endregion | - | This error means you have declared an end region in your code, without defining a start region. | +Ten błąd oznacza, że zadeklarowałeś w swoim kodzie region końcowy, bez zdefiniowania regionu początkowego. | |
Unclosed #region found at end of script | +Niezamknięty #region znaleziony na końcu skryptu | - | This error means you have declared a region somewhere in the code but have not defined an end region anywhere for it. | +Ten błąd oznacza, że zadeklarowałeś region gdzieś w kodzie, ale nie zdefiniowałeś dla niego nigdzie regionu końcowego. | |
Unexpected terminal operator [val] | +Nieoczekiwany operator terminala [val] | - | This means there is an internal AST Validation Error (you should never see this error, but if you do please consider filing a bug report from the Help Menu) | +Oznacza to, że wystąpił wewnętrzny błąd walidacji AST (nie powinieneś nigdy zobaczyć tego błędu, ale jeśli tak się stanie, rozważ zgłoszenie błędu z menu Pomoc) | |
Unexpected unary operator [val] | +Nieoczekiwany operator jednoargumentowy [val] | - | This happens when a unary operator (like +, -, =, etc...) has been found in your code at a place when it isn't expected, where [val] will show you the operator. | +Dzieje się tak, gdy operator jednoargumentowy (jak +, -, =, itd...) został znaleziony w twoim kodzie w miejscu, w którym nie jest oczekiwany, gdzie [val] pokaże ci ten operator. | |
Unexpected ternary operator [val] | +Nieoczekiwany operator trójskładnikowy [val] | - | This error means you have used one of the parts of the ternary operator incorrectly somewhere in your code, where [val] shows the part that is in error. | +Ten błąd oznacza, że gdzieś w swoim kodzie użyłeś niepoprawnie jednej z części operatora trójskładnikowego, gdzie [val] wskazuje część, która jest w błędzie. | |
Try needs to have catch or finally clause | +Próba musi mieć klauzulę catch lub finally | - | This error means you have called the try function but have omitted to include a catch or finally clause. | +Ten błąd oznacza, że wywołałeś funkcję try, ale pominąłeś włączenie klauzuli catch lub finally. | |
Macro [val] already exists | +Makro [val] już istnieje | - | You can get this error when you try to define a macro [val] with the same name as one that has been previously defined. | +Ten błąd możesz otrzymać, gdy próbujesz zdefiniować makro [val] o tej samej nazwie, co makro, które zostało wcześniej zdefiniowane. | |
Malformed variable reference, got [val] | - | This means there is an internal AST Validation Error (you should never see this error, but if you do please consider filing a bug report from the Help Menu) | +Oznacza to, że wystąpił wewnętrzny błąd walidacji AST (nie powinieneś nigdy zobaczyć tego błędu, ale jeśli tak się stanie, rozważ zgłoszenie błędu z menu Pomoc) | ||
Assignment to multi-relational-equality expression - GML does not support multiple assignments in an expression | +Przypisanie do wyrażenia typu multi-relational-equality - GML nie obsługuje wielu przypisań w wyrażeniu | - | This error tells you there is an issue with a multi-operator assignment (also called a compound assignment) which is not supported by the GameMaker Language. This includes things like "*=" or "/=", etc... | +Ten błąd informuje, że występuje problem z przypisaniem wielu operatorów (zwanym również przypisaniem złożonym), które nie jest obsługiwane przez GameMaker Language. Obejmuje to rzeczy takie jak "*=" lub "/=", itp. | |
Macro [val] is unused | -- | This happens when the macro [val] is unused anywhere in your code. | +Makro [val] jest nieużywane | ++ | Dzieje się tak, gdy makro [val] jest nieużywane w dowolnym miejscu twojego kodu. |
Variable [val] only referenced once | -- | This means that the given variable [val] is only referenced once in your code. | +Zmienna [val] ma tylko jedno odniesienie | ++ | Oznacza to, że dana zmienna [val] jest tylko raz przywoływana w twoim kodzie. |
Unassigned variable [val] referenced | -- | This means that the variable [val] has been referenced in your code, but has not been assigned a value anywhere previously. | +Odwołanie do nieprzypisanej zmiennej [val] | ++ | Oznacza to, że zmienna [val] została przywołana w twoim kodzie, ale nigdzie wcześniej nie przypisano jej wartości. |
Only functions that are declared as constructors can use inheritance | +Tylko funkcje, które są zadeklarowane jako konstruktory mogą używać dziedziczenia | - | This error tells you that you have tried to use inheritance on a function which has not been declared as a constructor. | +Ten błąd mówi ci, że próbowałeś użyć dziedziczenia na funkcji, która nie została zadeklarowana jako konstruktor. | |
Unknown function attribute [val] | +Nieznany atrybut funkcji [val] | - | This error means that you have tried to use an invalid or unidentified function modifier ([val]) when declaring an in-kine function (a function modifier is something like the constructor keyword, which is supported). | +Ten błąd oznacza, że próbowałeś użyć nieprawidłowego lub niezidentyfikowanego modyfikatora funkcji ([val]) podczas deklarowania funkcji in-kine (modyfikator funkcji jest czymś takim jak słowo kluczowe constructor, które jest obsługiwane). | |
Inherited argument \"[val]\" is not in function arguments | -- | This error happens when you try to reference an argument in an inherited function that has not been declared in the parent function definition. | +Argument odziedziczony \"[val]\" nie występuje w argumentach funkcji | ++ | Ten błąd występuje, gdy próbujesz odwołać się do argumentu w funkcji dziedziczonej, która nie została zadeklarowana w definicji funkcji nadrzędnej. |
[val] Creation Code | -- | This happens when you have an error [val] in the room creation code somewhere. | +Kod tworzenia [val] | ++ | Dzieje się tak, gdy masz gdzieś błąd [val] w kodzie tworzenia room. |
When Feather is enabled the Syntax Errors window is replaced by the Feather Messages window:
-The Feather Messages window lists the errors and warnings that Feather encounters in your code, as well as the suggestions that it gives when it finds certain specific code patterns. Which types of errors are shown here depends on the profile that you define in the Feather Settings under Message Severity.
-In this window the list of messages can be sorted ascending or descending by message code, by message text (alphabetically) or by resource (alphabetically by resource name). You can also search using the search box in the top right corner of the window.
-Feather messages fall into three categories:
+Gdy Feather jest włączony, okno Syntax Errors jest zastępowane przez okno Feather Messages:
+Okno Feather Messages zawiera listę błędów i ostrzeżeń, które Feather napotyka w Twoim kodzie, jak również sugestie, które daje, gdy znajdzie pewne określone wzorce kodu. To, jakie typy błędów są tutaj pokazywane, zależy od profilu, który definiujesz w Ustawieniach Feathera w sekcji Message Severity.
+W tym oknie lista wiadomości może być sortowana rosnąco lub malejąco według kodu wiadomości, według tekstu wiadomości (alfabetycznie) lub według zasobu (alfabetycznie według nazwy zasobu). Można również wyszukiwać za pomocą pola wyszukiwania w prawym górnym rogu okna.
+Wiadomości z piór dzielą się na trzy kategorie:
+
-
This guide briefly covers how to build and use primitives using custom vertex formats and vertex buffers.
-In general when you start working with 3D, special effects, complex drawing processes or shaders you don't need to worry too much about the vertex format being used, since GameMaker will automatically set up and pass through the vertex data for you. However, sometimes it is necessary to create your own vertex data and format it to suit, especially when you need to boost speed, or wish to pass in extra information. For example the standard vertex format includes an x, y, z 3D position, colour (with alpha), and UV texture coordinates, which, if you were creating it yourself, would look something like:
+W tym podręczniku omówiono pokrótce sposób tworzenia i używania prymitywów przy użyciu niestandardowych formatów wierzch ołków i buforów wierzchołków.
+Na ogół, gdy zaczynasz pracę z 3D, efektami specjalnymi, złożonymi procesami rysowania lub stroną shaders, nie musisz się zbytnio przejmować używanym formatem vertex, ponieważ GameMaker automatycznie skonfiguruje i przepuści dane wierzchołków. Czasami jednak konieczne jest utworzenie własnych danych vertex i odpowiednie ich sformatowanie, zwłaszcza gdy chcesz zwiększyć szybkość lub przekazać dodatkowe informacje. Na przykład standardowy format vertex zawiera pozycję 3D x, y, z, kolor (z alfą) oraz współrzędne UV texture. Gdybyś sam tworzył takie dane, wyglądałyby one następująco
vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
- vertex_format_add_texcoord();
+ vertex_format_add_textcoord();
my_format = vertex_format_end();
However, if you are only using (for example) a shader to manipulate the position of the vertex, then there would be no need to pass through colour or texture data. In this case you would create your own format as so:
+Jeśli jednak używasz (na przykład) adresu shader tylko do manipulowania położeniem adresu vertex, nie ma potrzeby przekazywania danych o kolorze ani adresu texture. W takim przypadku należy utworzyć własny format w następujący sposób:
vertex_format_begin();
vertex_format_add_position_3d();
my_format = vertex_format_end();
In total there are five different vertex attributes that you can use when defining a vertex format:
+W sumie istnieje pięć różnych atrybutów vertex, których można użyć podczas definiowania formatu vertex:
In general you must always provide position or 3D position as part of the format, but all the others are optional.
-You should note that once you have created your vertex format, the order in which you have defined the vertex attributes must be honoured when building your primitives. So, if you have defined a vertex format as position, colour, and texture coordinate, then you must add these attributes to the primitive in the same order otherwise you will get an error. Also note that like any other dynamic resource, a vertex format requires memory and therefore should be removed when not needed using the function vertex_format_delete.
-Any primitives that you build are held in a vertex buffer. This must be created beforehand and then referenced by the functions that are used to build your primitive. The vertex buffer can be reused as many times as necessary to create different primitives, or it can be "frozen" to maintain a specific primitive type for the duration of your game or level (which is the fastest approach, so if you know that a primitive you build will not change then you should always use this option).
-An example of a single triangle primitive being built is shown in the following code:
+Ogólnie rzecz biorąc, w formacie należy zawsze podawać pozycję lub pozycję 3D, ale wszystkie pozostałe elementy są opcjonalne.
+Należy pamiętać, że po utworzeniu formatu vertex kolejność, w jakiej zostały zdefiniowane atrybuty vertex, musi być przestrzegana podczas tworzenia prymitywów. Tak więc, jeśli zdefiniowałeś format vertex jako pozycję, kolor i współrzędną texture, musisz dodać te atrybuty do prymitywu w tej samej kolejności, w przeciwnym razie pojawi się błąd. Należy również pamiętać, że jak każdy inny zasób dynamiczny, format vertex wymaga pamięci i dlatego powinien być usuwany, gdy nie jest potrzebny, za pomocą funkcji vertex_format_delete().
+Wszystkie prymitywy, które zostaną zbudowane, są przechowywane w buforze wierzchołków. Bufor ten musi być utworzony wcześniej, a następnie odwołują się do niego funkcje używane do budowania prymitywów. Strona vertex buffer może być używana tyle razy, ile jest to konieczne do tworzenia różnych prymitywów, lub może zostać "zamrożona", aby zachować określony typ prymitywu na czas trwania gry lub poziomu (jest to najszybsze rozwiązanie, więc jeśli wiesz, że zbudowany prymityw nie ulegnie zmianie, zawsze powinieneś korzystać z tej opcji).
+Przykład budowy prymitywu pojedynczego trójkąta jest przedstawiony w poniższym kodzie:
// CREATE EVENT
v_buff = vertex_create_buffer();
vertex_begin(v_buff, global.my_format);
@@ -58,87 +58,88 @@
Here we have first created our vertex buffer in the Create Event of the instance, then we begin the definition of the different vertices that make up our triangle primitive, giving the position, the colour, and the texture UV coordinate for each of the three points that we want to use. We then end the vertex definition, and we know that the vertex buffer with this vertex data is stored in the variable "v_buff".
-If the contents of the buffer are going to be updated constantly, the buffer would be created, given the vertex data, and then be destroyed again - after it's been drawn - all in the same step.
-We then draw the contents of the vertex buffer in the Draw Event using a shader. This is a very simple example, and is basically how GameMaker works internally, ie: When you draw a sprite, GameMaker creates a vertex buffer with four vertices creating two triangles (which make a square, also called a "quad"), and textures these two triangles with the sprite image. When we draw this sprite, we are submitting the vertex buffer and its contents are drawn to the screen.
-You'll notice when we submit the vertex buffer for drawing, we supply a primitive type. The type of primitive you use can be a point, a line list or strip, or a triangle list or strip, but you are not permitted triangle fans since most mobile hardware will not accept that primitive type. Don't forget to format your vertex buffer correctly for the type of primitive that is going to be used to draw it. For example, drawing a two triangle primitive as a triangle list requires 6 points, but as a triangle strip it only requires 4 points. Which type you use is up to you and will depend on what you are wanting to draw and the effect that you want to achieve.
-One final important point to note when using your own vertex buffers in this way is how it affects the vertex batches that are sent to the GPU. When you create a vertex buffer you are creating the lowest level of graphics data, so when you draw all that happens is that GameMaker sends your buffer directly to the graphics card. Because of this, if you want better batching, you must work it out yourself and store the things you want to batch inside the same buffer.
-As we have already mentioned above, vertex formats are built up by using together the following 5 attribute types (added via the appropriate vertex_format_add_* function):
+W tym przypadku najpierw tworzymy nasz wierzchołek buffer w zdarzeniu Create Event instancji, a następnie rozpoczynamy definicję różnych wierzchołków, które tworzą nasz prymityw trójkąta, podając pozycję, kolor i współrzędną UV texture dla każdego z trzech punktów, których chcemy użyć. Następnie kończymy definicję vertex i wiemy, że strona vertex buffer z danymi vertex jest przechowywana w zmiennej "v_buff".
+UWAGA: Jeśli zawartość strony buffer ma być stale aktualizowana, można by utworzyć stronę buffer, przekazać jej dane vertex, a następnie ponownie ją zniszczyć - po narysowaniu - wszystko w tym samym kroku.
+Następnie w zdarzeniu Draw Event rysujemy zawartość strony vertex buffer za pomocą strony shader. Jest to bardzo prosty przykład i w zasadzie tak właśnie działa GameMaker, tzn. gdy rysujesz stronę sprite, strona GameMaker tworzy stronę vertex buffer z czterema wierzchołkami tworzącymi dwa trójkąty (które tworzą kwadrat, zwany też "quadem"), a strona textures tworzy z tych dwóch trójkątów obraz sprite. Podczas rysowania tej strony sprite przesyłamy na ekran obraz vertex buffer i jego zawartość.
+Po przesłaniu strony vertex buffer do narysowania podajemy typ prymitywu. Prymityw może być punktem, listą lub paskiem linii albo listą lub paskiem trójkątów, ale nie wolno używać trójkątów, ponieważ większość urządzeń przenośnych nie akceptuje tego typu prymitywów. Nie zapomnij sformatować strony vertex buffer poprawnie dla typu prymitywu, który ma być użyty do jej narysowania. Na przykład, rysowanie prymitywu dwóch trójkątów jako listy trójkątów wymaga 6 punktów, ale jako paska trójkątów wymaga tylko 4 punktów. To, którego typu użyjesz, zależy od tego, co chcesz narysować i jaki efekt chcesz osiągnąć.
+Ostatnią ważną kwestią, na którą należy zwrócić uwagę, używając w ten sposób własnej strony vertex buffers, jest to, jak wpływa ona na partie wierzchołków wysyłane do GPU. Gdy tworzysz vertex buffer, tworzysz najniższy poziom danych graficznych, więc podczas rysowania wszystko, co się dzieje, to fakt, że GameMaker wysyła buffer bezpośrednio do karty graficznej. Z tego powodu, jeśli chcesz uzyskać lepszy podział na partie, musisz to zrobić samodzielnie i przechowywać elementy, które chcesz podzielić na partie, w tej samej witrynie buffer.
+Jak już wspomniano powyżej, formaty vertex są tworzone poprzez łączne wykorzystanie następujących 5 typów atrybutów (dodawanych za pomocą odpowiedniej funkcji vertex_format_add_* ):
Within the GLSL ES shader, these kinds are recognised using the following 4 attributes:
+W języku GLSL ES shader rodzaje te są rozpoznawane za pomocą następujących 4 atrybutów:
Now, this might look odd as it seems that we can specify more attribute kinds in our vertex format than we can in the vertex shader. However, in the shader Position and 3D Position are treated as the same attribute, except that Position is expected to have only "x" and "y" coordinates whereas 3D Position has “x”, “y” and “z” coordinates. So how do you map what's in your vertex format to how you define attributes in your shader? Let's start by looking at a typical set of attributes from the default shader:
-+
Może to wyglądać dziwnie, ponieważ wydaje się, że w naszym formacie vertex możemy określić więcej rodzajów atrybutów niż w vertex shader. Jednak w formacie shader Position i 3D Position są traktowane jako te same atrybuty, z tym wyjątkiem, że Position ma mieć tylko współrzędne "x" i "y", podczas gdy 3D Position ma współrzędne "x", "y" i "z". Jak więc odwzorować to, co jest w formacie vertex, na sposób definiowania atrybutów w shader? Na początek przyjrzyjmy się typowemu zestawowi atrybutów z domyślnego shadera:
+
attribute vec3 in_Position; // (x,y,z)
//attribute vec3 in_Normal; // (x,y,z) unused in this shader.
attribute vec4 in_Colour; // (r,g,b,a)
attribute vec2 in_TextureCoord; // (u,v)
And here's a chunk of code which sets up a vertex format compatible with this shader:
+A oto fragment kodu, który ustawia format vertex kompatybilny z tym shaderem:
vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
- vertex_format_add_texcoord();
+ vertex_format_add_textcoord();
my_format = vertex_format_end();
Now, how does the shader attribute get matched to the vertex format type? It's just based on the naming convention:
+W jaki sposób atrybut shader jest dopasowywany do typu formatu vertex? Opiera się to na konwencji nazewnictwa:
Now, things get trickier when you have multiple attributes of the same kind, but things are still based on the same naming convention. We'll look at supplying additional colour and texture coordinates now, as there can only be one Position and one Normal attribute in the shader or vertex format, but there can be multiple colour or texture attributes.
-When adding additional colour attributes to your shader, a number needs to be added to the end of the shader attribute to indicate which particular entry in the vertex format the attribute maps to. Here's an example - first the vertex format:
+Sytuacja komplikuje się, gdy mamy wiele atrybutów tego samego rodzaju, ale nadal stosujemy tę samą konwencję nazewnictwa. Przyjrzymy się teraz dostarczaniu dodatkowych współrzędnych koloru i tekstury, ponieważ w formacie shader lub vertex może być tylko jeden atrybut Pozycja i jeden atrybut Normalny, ale może być wiele atrybutów koloru lub texture.
+Podczas dodawania dodatkowych atrybutów koloru do strony shader na końcu atrybutu shader należy dodać numer wskazujący, do którego wpisu w formacie vertex atrybut ten jest przypisany. Oto przykład - najpierw format vertex:
vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_colour();
- vertex_format_add_texcoord();
+ vertex_format_add_textcoord();
my_format = vertex_format_end();
And now the associated shader attributes:
+A teraz powiązane atrybuty shader:
attribute vec3 in_Position; // (x,y,z)
attribute vec4 in_Colour0; // (r,g,b,a)
attribute vec4 in_Colour1; // (r,g,b,a)
attribute vec2 in_TextureCoord; // (u,v)
In this case in_Colour0 maps to the first vertex_format_add_colour() and in_Colour1 maps to the second.
-Texture coordinates are handled slightly differently to colour. Basically, anything which isn't called in_Position, in_Normal or one of the in_Colour[0 ... ] attributes is treated as a texture coordinate. The order they are defined in, in the list of attributes in the shader, is what denotes which attribute in the vertex format they map to. See the following GML example:
+W tym przypadku adres in_Colour0 odpowiada pierwszemu adresowi vertex_format_add_colour(), a adres in_Colour1 odpowiada drugiemu.
+Współrzędne tekstury są traktowane nieco inaczej niż kolor. Zasadniczo wszystko, co nie ma nazwy in_Position, in_Normal lub jednego z atrybutów in_Colour[0 ... ], jest traktowane jako współrzędna texture. Kolejność, w jakiej są one zdefiniowane na liście atrybutów w witrynie shader, określa, do którego atrybutu w formacie vertex są one mapowane. Patrz następujący przykład GML:
vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
- vertex_format_add_texcoord();
- vertex_format_add_texcoord();
- vertex_format_add_texcoord();
+ vertex_format_add_textcoord();
+ vertex_format_add_textcoord();
+ vertex_format_add_textcoord();
my_format = vertex_format_end();
And the shader code would look something like this:
+Kod shader wyglądałby mniej więcej tak:
attribute vec3 in_Position; // (x,y,z)
attribute vec4 in_Colour; // (r,g,b,a)
attribute vec2 in_myTexcoord; // (u,v)
attribute vec2 in_TextureCoord; // (u,v)
attribute vec2 in_Something; // (u,v)
In this example, in_myTexcoord, in_TextureCoord and in_Something map to the three successive texture coordinate attributes defined in the vertex format.
-You can find a full list of all the functions required to create vertex formats, vertex buffers and primitives from the following page:
+W tym przykładzie adresy in_myTexcoord, in_TextureCoord i in_Something odpowiadają trzem kolejnym atrybutom współrzędnych texture zdefiniowanym w formacie vertex.
+Pełną listę wszystkich funkcji potrzebnych do tworzenia formatów vertex, vertex buffers i prymitywów można znaleźć na następnej stronie:
--
+
+
+
-
If you've been using GameMaker for any length of time, you will almost certainly have come across blend modes, and probably even used them in your games. Blend modes are a great way to change how something is drawn to give interesting and specific graphical effects, but do you know how they work and how do you use them? This is a subject that can confuse people and so in this section we hope to dispel some of the mystery surrounding blend modes and enable you to use them to their fullest extent in your games.
--
Blend modes basically tell your game to draw certain things blended with whatever else is already drawn beforehand. Everything you draw to the screen is made up of four component parts - red, green, blue and alpha - and by default they are drawn to the screen using the blend mode bm_normal. This blend mode draws all pixels with their colour and alpha values essentially unchanged (although, later in this section you'll see that this isn't quite true...), but GameMaker has a number of built in blend modes that can be set to change this behaviour.
-When GameMaker goes to draw a pixel there's a source colour (the colour of the pixel you are going to draw) and a destination colour (the colour that's already in the pixel we're drawing to). When determining the new colour of the pixel, GameMaker will combine the source and destination colours according to the blend mode, as mentioned above. Each component of the colours is stored as a floating point value between 0 and 1, and the new colour is calculated by multiply each component of the source colour by some factor and by multiplying each component of destination colour by some other factor and then adding the results together component by component.
--
GameMaker uses the function gpu_set_blendmode() to change the blending that your game uses for drawing. You would call this before (for example) drawing a sprite, then set it back again afterwards, something like this:
+Jeśli korzystasz z GameMakera przez dłuższy czas, z pewnością zetknąłeś się z trybami mieszania, a prawdopodobnie nawet używałeś ich w swoich grach. Tryby mieszania to świetny sposób, by zmienić sposób rysowania czegoś w celu uzyskania interesujących i specyficznych efektów graficznych, ale czy wiesz, jak one działają i jak z nich korzystać? Jest to temat, który może wprawiać ludzi w zakłopotanie, dlatego w tym rozdziale mamy nadzieję rozwiać część tajemnic związanych z trybami mieszania i umożliwić ich pełne wykorzystanie w grach.
++
Tryby mieszania pozwalają grze na rysowanie pewnych elementów w połączeniu z innymi, już narysowanymi wcześniej. Wszystko, co rysujesz na ekranie, składa się z czterech części składowych - czerwonej, zielonej, niebieskiej i alfa - i domyślnie jest rysowane na ekranie przy użyciu trybu mieszania bm_normal. Ten tryb mieszania rysuje wszystkie piksele z ich kolorami i wartościami alfa w zasadzie bez zmian (choć w dalszej części tego rozdziału zobaczysz, że to nie do końca prawda...), ale GameMaker ma wiele wbudowanych trybów mieszania, które można ustawić, by zmienić to zachowanie.
+Gdy w programie GameMaker chcemy narysować piksel, mamy do dyspozycji kolor źródłowy (kolor piksela, który chcemy narysować) i kolor docelowy (kolor, który już znajduje się w pikselu, do którego rysujemy). Podczas określania nowego koloru piksela strona GameMaker połączy kolory źródłowy i docelowy zgodnie z trybem mieszania, jak wspomniano powyżej. Każdy składnik kolorów jest przechowywany jako wartość zmiennoprzecinkowa z zakresu od 0 do 1, a nowy kolor jest obliczany przez pomnożenie każdego składnika koloru źródłowego przez pewien współczynnik oraz przez pomnożenie każdego składnika koloru docelowego przez inny współczynnik, a następnie zsumowanie wyników składnik po składniku.
++
GameMaker używa funkcji gpu_set_blendmode() do zmiany sposobu mieszania, jakiego używa gra podczas rysowania. Możesz ją wywołać przed (na przykład) narysowaniem strony sprite, a następnie ustawić ją ponownie po zakończeniu rysowania, coś w tym stylu:
gpu_set_blendmode(bm_add);
draw_self();
gpu_set_blendmode(bm_normal);
That code draws the instance sprite using an additive blend mode. The additive blend mode is set using one of the available GML constants, of which there are four for basic modes:
+Ten kod rysuje instancję sprite przy użyciu addytywnego trybu mieszania. Tryb mieszania addytywnego jest ustawiany za pomocą jednej z dostępnych stałych GML, z których cztery są dostępne dla trybów podstawowych:
bm_normal
bm_add
bm_subtract
bm_max
We have seen already how bm_normal looks - since that's what everything defaults to! - so let's continue on to look at the other three in a bit more detail...
+Widzieliśmy już, jak wygląda strona bm_normal - ponieważ jest to domyślne ustawienie wszystkiego! - przyjrzyjmy się więc pozostałym trzem stronom nieco bardziej szczegółowo...
-+
This blend mode adds the colours of the source and destination pixels together (but does not affect the alpha values). For example, if your background image is a solid colour with an RGB value of (100,15,70), and then you draw a rectangle with an RGB of (120,25,30), then (using bm_add) the fina RGB values for each pixel of the rectangle would be (220,40,100). Note that colour values can't go over 255 (or under 0), so anything that adds up to more than that will be clamped to 255.
-Using this blend mode is a great way to get that "neon glow" look, and is most often used for lighting effects, or lasers or just about anything that you want to appear to glow or have luminescence.
-+
Ten tryb mieszania sumuje kolory pikseli źródłowych i docelowych (ale nie ma wpływu na wartości alfa). Na przykład, jeśli obraz tła jest jednolitym kolorem o wartości RGB (100,15,70), a następnie narysujesz prostokąt o wartości RGB (120,25,30), to (używając bm_add) końcowe wartości RGB dla każdego piksela prostokąta będą wynosiły (220,40,100). Zauważ, że wartości kolorów nie mogą przekraczać 255 (lub być mniejsze od 0), więc wszystko, co daje więcej niż ta wartość, zostanie zaciśnięte na 255.
+Ten tryb mieszania to świetny sposób na uzyskanie efektu "neonowej poświaty". Najczęściej jest on używany do tworzenia efektów świetlnych, laserów i innych elementów, które mają sprawiać wrażenie świecących lub luminescencyjnych.
+
This blend mode is a bit different to the previous one, as it it works on a percentage basis rather than a direct value. This percentage is what will be subtracted from the destination colour (the colour of the pixel being drawn to). To explain this better, let's look at an example.
-Imagine you want to reduce the red value of all pixels drawn in an area of the room by 25%. You would first need to get 25% of 255, then convert that into an RGB colour value, and then finally use that along with bm_subtract to draw over the area. Something like this:
+Ten tryb mieszania różni się nieco od poprzedniego, ponieważ działa na zasadzie procentowej, a nie bezpośredniej wartości. Wartość procentowa jest tym, co zostanie odjęte od koloru docelowego (koloru piksela, do którego rysowany jest obraz). Aby lepiej to wyjaśnić, przyjrzyjmy się przykładowi.
+Wyobraź sobie, że chcesz zmniejszyć wartość koloru czerwonego wszystkich pikseli narysowanych w obszarze room o 25%. Musiałbyś najpierw uzyskać 25% z 255, następnie przekonwertować to na wartość koloru RGB, a na koniec użyć tego wraz z bm_subtract do narysowania obszaru. Coś w tym stylu:
var red = (25 / 100) * 255;
var col = make_colour_rgb(red, 0, 0);
gpu_set_blendmode(bm_subtract);
draw_rectangle_colour(0, 0, 128, 256, col, col, col, col, false);
gpu_set_blendmode(bm_normal);
Following the same rule, if you wanted to simply reduce the brightness of a background by 50% then you would have a colour that is 50% red, 50% green and 50% blue, ie: RGB (128, 128, 128). This blend mode is mainly used for drawing shadows, or creating interesting fade out effects.
-+
Zgodnie z tą samą zasadą, jeśli chcesz po prostu zmniejszyć jasność tła o 50%, uzyskasz kolor, który jest w 50% czerwony, w 50% zielony i w 50% niebieski, czyli RGB (128, 128, 128). Ten tryb mieszania jest używany głównie do rysowania cieni lub tworzenia ciekawych efektów wygaszania.
+
This blend mode is more complex to explain, but it basically multiplies the source colours by the source alpha, then adds them to the destination colour values multiplied by the inverse source colour values. The actual maths behind bm_max (and the other blend modes) we'll cover in part two of our article, but all you need to know is that the result will be a more "saturated" and brighter colour, without leading to the same pure white brilliance that using bm_add will cause.
-This blend mode can be useful when you need to draw overlapping images without them becoming so bright that they can't be seen. The bright parts will become brighter, but they should still maintain a level of colour and hue. Note though that the alpha value of the source image will also influence in the final effect when using this blend mode.
+Ten tryb mieszania jest bardziej skomplikowany do wyjaśnienia, ale w zasadzie mnoży on kolory źródłowe przez źródłową alfę, a następnie dodaje je do wartości kolorów docelowych pomnożonych przez odwrotność wartości kolorów źródłowych. Właściwą matematykę kryjącą się za bm_max (i innymi trybami mieszania) omówimy w drugiej części naszego artykułu, ale wystarczy wiedzieć, że rezultatem będzie bardziej "nasycony" i jaśniejszy kolor, nie prowadzący do tego samego czystego białego blasku, który spowoduje użycie bm_add.
+Ten tryb mieszania może być przydatny, gdy trzeba narysować nakładające się na siebie obrazy, a jednocześnie nie mogą one stać się tak jasne, że nie będzie ich widać. Jasne części staną się jaśniejsze, ale nadal powinny zachować odpowiedni poziom koloru i odcienia. Należy jednak pamiętać, że wartość alfa obrazu źródłowego również będzie miała wpływ na efekt końcowy przy użyciu tego trybu mieszania.
-
Now you know the very basics behind using a blend mode in GameMaker. It takes the RGB and alpha values for the source image (what is being drawn) and it then blends these with the RGB and alpha values of the destination (what is being drawn too). This blending is done by multiplying the individual components for each pixel colour and alpha by different amounts, depending on the effects that we wish to achieve. With this knowledge, you can start to use blend modes in your games to get glowing lasers, realistic shadows, or saturated transition effects, but there is still more to be learned here! Below we look at the extended blend modes, as well as explore a bit of the maths behind them, so that you can create your own blending effects like multiply or overlay.
--
Above we have talked about the function gpu_set_blendmode(), but now we are going to look at gpu_set_blendmode_ext(). This is (as the name implies) an extended function to set custom blend modes, but how does this work? Let's just have a look at the dry technical answer first before we go any further:
++
Teraz znasz już podstawy używania trybu mieszania w programie GameMaker. Tryb ten pobiera wartości RGB i alfa obrazu źródłowego (tego, co jest rysowane), a następnie miesza je z wartościami RGB i alfa obrazu docelowego (tego, co też jest rysowane). Mieszanie odbywa się poprzez mnożenie poszczególnych składowych dla każdego koloru piksela i alfa przez różne wartości, w zależności od efektów, jakie chcemy uzyskać. Mając tę wiedzę, możesz zacząć używać trybów mieszania w swoich grach, aby uzyskać świecące lasery, realistyczne cienie lub nasycone efekty przejścia, ale wciąż jest jeszcze wiele do nauczenia się! Poniżej przyjrzymy się rozszerzonym trybom mieszania, a także zgłębimy nieco matematyki, która się za nimi kryje, abyś mógł tworzyć własne efekty mieszania, takie jak mnożenie czy nakładanie.
++
Powyżej omówiliśmy funkcję gpu_set_blendmode()teraz zajmiemy się gpu_set_blendmode_ext(). Jest to (jak sama nazwa wskazuje) rozszerzona funkcja do ustawiania niestandardowych trybów mieszania, ale jak to działa? Zanim przejdziemy dalej, zapoznajmy się z suchą, techniczną odpowiedzią:
Now, while that text is correct and explains what blend modes do, it's not really intuitive... so let's go into a bit more detail and explain what this is all about.
-When we talk about the source we are talking about the colour and alpha values of the pixel that is being drawn, and when we talk about the destination we are talking about the colour and alpha values of the pixel that it is being drawn over. To keep things easier we can write out the source colour as it's components, like this:
+Chociaż tekst ten jest poprawny i wyjaśnia, na czym polegają tryby mieszania, nie jest zbyt intuicyjny... Dlatego też omówmy go nieco dokładniej i wyjaśnijmy, o co w tym wszystkim chodzi.
+Gdy mówimy o źródle , mamy na myśli kolor i wartości alfa rysowanego piksela, a gdy mówimy o miejscu docelowym , mamy na myśli kolor i wartości alfa piksela, nad którym jest ono rysowane. Aby ułatwić sobie pracę, możemy zapisać kolor źródłowy jako jego składowe, na przykład tak:
And the destination would be like this:
+A cel podróży wyglądałby tak:
So when we draw something on the screen, our graphics processor is actually doing the following for every single pixel:
+Kiedy więc rysujemy coś na ekranie, nasz procesor graficzny wykonuje następujące czynności dla każdego piksela:
final_pixel_colour = (Rs,Gs,Bs,As) * source_blend_factor + (Rd,Gd,Bd,Ad) * destination_blend_factor
-The blend factors mentioned above are defined in GameMaker by a number of GML constants, and each one represents a factor by which the source or destination R, G, B and A values should be multiplied by. The factors available are:
+Wspomniane wyżej współczynniki mieszania są zdefiniowane w programie GameMaker za pomocą kilku stałych GML, a każdy z nich reprezentuje współczynnik, przez który należy pomnożyć źródłowe lub docelowe wartości R, G, B i A. Dostępne są następujące współczynniki:
The four "basic" blend modes that GameMaker has are actually composites of two of these blend factors.
-Example of how bm_normal Works
+Cztery "podstawowe" tryby mieszania dostępne w programie GameMaker są w rzeczywistości kompozycjami dwóch z tych czynników mieszania.
+Time to look at a practical example of how this comes together for drawing in GameMaker. For this, we are going to look at bm_normal, which is really:
+Czas przyjrzeć się praktycznemu przykładowi, jak to się łączy w rysowaniu w GameMakerze. W tym celu przyjrzymy się bm_normal, który jest naprawdę:
gpu_set_blendmode_ext(bm_src_alpha, bm_inv_src_alpha);
-One of the problems people have with blend modes is visualising the results, so to show the maths behind them, we'll use this blend mode as our test subject since it's the blend mode that everyone uses the most and we know exactly what to expect from it. Imagine we are drawing a rectangle with the colour (128, 255, 64, 255) over a background with the colour (64, 128, 255, 255):
-So, our blend mode looks like this:
+Jednym z problemów, z jakimi borykają się użytkownicy trybów mieszania, jest wizualizacja wyników, dlatego aby pokazać, na czym polega matematyka, użyjemy tego trybu mieszania jako obiektu testowego, ponieważ jest on najczęściej używany przez wszystkich i wiemy dokładnie, czego można się po nim spodziewać. Wyobraźmy sobie, że rysujemy prostokąt o kolorze (128, 255, 64, 255) na tle o kolorze (64, 128, 255, 255):
+Tak więc nasz tryb mieszania wygląda następująco:
Source: (128, 255, 64, 255) = (0.5, 1, 0.25, 1)
Destination: (64, 128, 255, 255) = (0.25, 0.5, 1, 1)
bm_src_alpha (As, As, As, As) = (255, 255, 255, 255) = (1, 1, 1, 1)
@@ -104,7 +104,7 @@
As you can see, we multiply the destination values by 0, which gives them a value of 0 too, meaning that the source colours are unchanged, so our final colour value is (128, 255, 64, 255). You can see how the inclusion of alpha affects this value too:
+Jak widać, mnożymy wartości docelowe przez 0, co również daje im wartość 0, co oznacza, że kolory źródłowe pozostają niezmienione, a więc nasza ostateczna wartość koloru wynosi (128, 255, 64, 255). Widać, jak włączenie alfa wpływa również na tę wartość:
Source (128, 255, 64, 128) = (0.5, 1, 0.25, 0.5)
Destination: (64, 128, 255, 255) = (0.25, 0.5, 1, 1)
bm_src_alpha (As, As, As, As) = (128, 128, 128, 128) = (0.5, 0.5, 0.5, 0.5)
@@ -112,51 +112,51 @@
This gives a final pixel colour (96, 192, 159, 192), and will give an image like that shown below:
- -Hopefully you can see clearly now what the blend mode factors do, and how combining them can change what is drawn to create some interesting effects. We will now look at a practical example of how to combine these factors to create your own custom blend modes.
--
+
W ten sposób uzyskasz ostateczny kolor pikseli (96, 192, 159, 192), a w efekcie obraz podobny do pokazanego poniżej:
+ +Mam nadzieję, że teraz wyraźnie widać, jak działają czynniki trybu mieszania i jak ich łączenie może zmienić rysowany obraz, tworząc interesujące efekty. Przyjrzymy się teraz praktycznemu przykładowi łączenia tych czynników w celu utworzenia własnych trybów mieszania.
++
Now you know how setting blend modes works and have seen an example of it being used for everyday drawing, let's look at something abit more complex...
--
Using the different factors available, you can create your own blend modes to achieve blending options that are not available to you normally. In this example, we are going to create a multiply effect like that used in Photoshop. We can simulate this blend mode using two of our above mentioned blend mode factor constants like this:
+Teraz, gdy już wiesz, jak działa ustawianie trybów mieszania i widziałeś przykład ich zastosowania w codziennym rysowaniu, przyjrzyjmy się czemuś bardziej złożonemu...
++
Korzystając z różnych dostępnych czynników, można tworzyć własne tryby mieszania, aby uzyskać opcje mieszania niedostępne w normalnych warunkach. W tym przykładzie zamierzamy utworzyć efekt mnożenia , taki jak w Photoshopie. Możemy zasymulować ten tryb mieszania, używając dwóch z wyżej wymienionych stałych współczynników trybu mieszania, jak poniżej:
gpu_set_blendmode_ext(bm_dest_colour, bm_zero);
-Before we actually draw something using this blend mode, let's have a look at how it should look in Photoshop:
-Using our extended blend mode we get the following:
+Zanim zaczniemy rysować coś przy użyciu tego trybu mieszania, zobaczmy, jak to powinno wyglądać w Photoshopie:
+Korzystając z rozszerzonego trybu mieszania, uzyskamy następujące wyniki:
(Rs, Gs, Bs, As) * (Rd, Gd, Bd, Ad) + (Rd, Gd, Bd, Ad) * (0,0,0,0) = (Rs, Gs, Bs, As) * (Rd, Gd, Bd, Ad)
Source colour * dest colour + dest colour * zero = source colour * dest colour
The blend factor bm_zero effectively removes the destination colour from the equation (as zero times anything is zero), so we are left with the source colour multiplied by the blend factor of the destination colour, hence the name "multiply" for the mode. To use this in GameMaker, you would simply have something like this in your Draw Event:
+Współczynnik mieszania bm_zero skutecznie usuwa kolor docelowy z równania (ponieważ zero razy cokolwiek jest zerem), więc pozostaje nam kolor źródłowy pomnożony przez współczynnik mieszania koloru docelowego, stąd nazwa trybu "multiply". Aby użyć tego trybu w programie GameMaker, wystarczy w zdarzeniu Draw wprowadzić coś takiego:
gpu_set_blendmode_ext(bm_dest_colour, bm_zero);
draw_self();
gpu_set_blendmode(bm_normal);
The next image was taken from a test project in GameMaker using this exact code:
-Can you spot the difference? Probably not! There will, however, be some deviation between the two due to differences between the render tools used, but it's almost exactly as you would expect. Note though that not all the blend modes used by art programs are available to you within GameMaker due to the fact some of them can actually force the colour values to go over 255 and so create special effects, but that doesn't mean you can't create passable imitations of these effects, or even brand new effects, using them.
-It's worth mentioning that with GameMaker you can take this one step further using the function gpu_set_blendmode_ext_sepalpha(). This permits you to separate out the alpha component of the different blend mode factors and use them individually to create even more possible combinations. We won't cover this function here as it's explained in depth already in the manual, but it's worth mentioning just so you know it's available for use.
--
One final thing is worth noting about blend modes, and that is how they affect the alpha component of a colour. When simply drawing to the application surface or the display buffer, you don't really need to take into consideration the destination alpha value as it will always be one. However surfaces that you make yourself are different, since you can clear a surface to have any alpha value from zero to one that you wish. This leads to some interesting effects that are contrary to what most people would expect.
-To illustrate this, we are going to look at drawing using the basic default bm_normal. Most people think that having a surface cleared to alpha 0, and then drawing something with an alpha of 0.5 will give a resulting alpha value 0.5 too... but this is not the case and is something that many people think is a "bug" in how GameMaker renders things. However, as you will see, it's not a bug at all!
-Say you have surface with every pixel at alpha 0, then you draw a circle on it with alpha 0.5 using the bm_normal blend mode. The entire surface is still going to be alpha 0, but in the circle the alpha will actually be 0.25, since:
+Następny obraz pochodzi z projektu testowego w witrynie GameMaker, w którym użyto dokładnie tego kodu:
+Czy potrafisz dostrzec różnicę? Prawdopodobnie nie! Będą jednak występować pewne odchylenia między nimi ze względu na różnice między używanymi narzędziami do renderowania, ale jest to prawie dokładnie tak, jak można by się spodziewać. Należy jednak pamiętać, że nie wszystkie tryby mieszania używane w programach artystycznych są dostępne w GameMakerze, ponieważ niektóre z nich mogą wymuszać przekroczenie wartości 255 i w ten sposób tworzyć efekty specjalne, ale nie oznacza to, że nie można za ich pomocą tworzyć udanych imitacji tych efektów, a nawet zupełnie nowych efektów.
+Warto wspomnieć, że w GameMakerze można pójść o krok dalej, korzystając z funkcji gpu_set_blendmode_ext_sepalpha(). Pozwala ona wyodrębnić składowe alfa różnych trybów mieszania i używać ich pojedynczo w celu tworzenia jeszcze większej liczby możliwych kombinacji. Nie będziemy tutaj omawiać tej funkcji, ponieważ jest ona szczegółowo opisana w podręczniku, ale warto o niej wspomnieć, abyś wiedział, że można z niej korzystać.
++
Warto jeszcze zwrócić uwagę na jedną rzecz związaną z trybami mieszania, a mianowicie na to, jak wpływają one na składową alfa koloru. Podczas rysowania na powierzchni aplikacji lub w buforze monitora nie trzeba brać pod uwagę docelowej wartości alfa, ponieważ zawsze będzie ona równa jeden. W przypadku powierzchni, które tworzysz samodzielnie, jest inaczej, ponieważ możesz nadać im dowolną wartość alfa w zakresie od zera do jednego. Prowadzi to do ciekawych efektów, które są sprzeczne z oczekiwaniami większości ludzi.
+Aby to zilustrować, przyjrzymy się rysowaniu przy użyciu podstawowej, domyślnej opcji bm_normal. Większość ludzi myśli, że jeśli powierzchnia jest wyczyszczona do wartości alfa 0, a następnie narysuje coś z alfą 0,5, to wynikowa wartość alfa też wyniesie 0,5... ale tak nie jest i wiele osób uważa to za "błąd" w sposobie renderowania w GameMakerze. Jednak, jak się przekonasz, to wcale nie jest błąd!
+Powiedzmy, że mamy powierzchnię, której każdy piksel ma alfę 0, a następnie rysujemy na niej okrąg z alfą 0,5 za pomocą trybu mieszania bm_normal. Cała powierzchnia nadal będzie miała alfa 0, ale w okręgu alfa będzie wynosić 0,25, ponieważ:
0.5 * 0.5 + 0 * 0.5 = 0.5 * 0.5 = 0.25
-If you then proceed to draw another circle in the existing circle, also with an alpha of 0.5, then the alpha outside the circles would be 0, in between the circles 0.25, and in the smaller circle it would be 0.375:
+Jeśli następnie narysujesz kolejny okrąg w istniejącym okręgu, również z alfą 0,5, to alfa poza okręgiem wyniesie 0, między okręgami 0,25, a w mniejszym okręgu 0,375:
0.5 * 0.5 + 0.25 * 0.5 = 0.25 + 0.125 = 0.375
-If you were to continue to draw a number of 0.5 alpha circles to a surface with 0 alpha, and then draw this surface to the room, you would be able to clearly see this:
-If you are still a bit confused about the alpha, try to picture it as just another colour. It behaves like a colour and all calculations on it are done in a similar manner. It's just not really visible, although the effect it has on other colours is. Which brings us to the final thing to note when using surfaces and blend modes (even bm_normal)...
-Even if the alpha of the surface is 0, the colour components are still there and exist and will influence in all blending operations. So drawing to a zero alpha cleared surface that has been cleared using the colour red (for example) will blend the source colours with the destination colours and give different effects to that which you may think. The above image was created on a surface cleared to black over a black background, but if we clear the surface to red, we get this instead:
-Hopefully you can now work out why this happens for yourself using the formulas I've outlined above and applying the appropriate figures for bm_normal.
--
-
+
Jeśli nadal będziesz rysować pewną liczbę okręgów o alfie 0,5 na powierzchni o alfie 0, a następnie narysujesz tę powierzchnię na stronie room, będziesz mógł to wyraźnie zobaczyć:
+Jeśli nadal nie wiesz, czym jest alfa, spróbuj wyobrazić ją sobie jako kolejny kolor. Zachowuje się jak kolor i wszystkie obliczenia na nim są wykonywane w podobny sposób. Po prostu nie jest widoczna, choć wpływ, jaki wywiera na inne kolory, jest widoczny. W ten sposób dochodzimy do ostatniej rzeczy, na którą należy zwrócić uwagę podczas używania powierzchni i trybów mieszania (nawet na stronie bm_normal)...
+Nawet jeśli alfa powierzchni jest równa 0, składowe koloru nadal tam są, istnieją i będą miały wpływ na wszystkie operacje mieszania. Zatem rysowanie na powierzchni o zerowej alfie, która została oczyszczona przy użyciu koloru czerwonego (na przykład), spowoduje mieszanie kolorów źródłowych z docelowymi i da inne efekty niż się wydaje. Powyższy obrazek został utworzony na czarnej powierzchni na czarnym tle, ale jeśli wyczyścimy powierzchnię na czerwono, otrzymamy taki efekt:
+Mam nadzieję, że teraz można samemu ustalić, dlaczego tak się dzieje, korzystając ze wzorów, które przedstawiłem powyżej, i stosując odpowiednie liczby dla strony bm_normal.
++
+
-
A buffer (in programming) is basically a space within the system memory that is used to store small packets of data for just about anything (for example: data transfer, collisions, colour data, etc.). Since it is held in system memory it is very fast to access, and a buffer would generally be used for very short-term storage, like receiving network information before processing it, or for storing a checkpoint in your game (this is explained in the example given further down the page).
-Buffers are created by allocating a space in the system memory, calculated in byte s, which is then reserved for your game as long as your game is running or until you delete the buffer using the appropriate function (you can find all the GML buffer functions listed here). This means that even when your game is not in focus (for example, on a mobile device when you take a call the game will be put into the background) the buffer will still exist, however if the game is closed or re-started the buffer will be lost.
-Restarting the game will not clear or delete the buffer! But it will prevent any further access to the previously created buffer as the ID handle will have been lost, causing a memory leak which will crash your game eventually. So, when re-starting a game, remember to delete any buffers first.
-GameMaker permits the creation of four different buffer types. The reason for this is that buffers are designed to be a highly optimised temporary storage medium, and as such you should create a buffer that is appropriate to the type of data that you wish it to store, otherwise you could get errors or cause a bottleneck in your code. Before explaining this further, let's look at the four available buffer types (defined as constants in GML):
-+
Strona buffer (w programowaniu) to miejsce w pamięci systemowej, które służy do przechowywania małych pakietów danych dotyczących praktycznie wszystkiego (np. transferu danych, kolizji, kolorów itp.). Ponieważ jest przechowywana w pamięci systemowej, dostęp do niej jest bardzo szybki, a buffer jest zwykle używana do bardzo krótkotrwałego przechowywania danych, na przykład do odbierania informacji z sieci przed ich przetworzeniem lub do przechowywania punktu kontrolnego w grze (wyjaśniono to w przykładzie podanym w dalszej części strony).
+Bufory są tworzone poprzez przydzielenie miejsca w pamięci systemowej , liczonego w bajtach, które jest następnie rezerwowane dla Twojej gry tak długo, jak gra jest uruchomiona, lub do momentu usunięcia buffer za pomocą odpowiedniej funkcji (wszystkie funkcje GML buffer znajdziesz tutaj). Oznacza to, że nawet jeśli gra nie jest w centrum uwagi (np. na urządzeniu przenośnym, gdy odbierasz połączenie, gra przechodzi w tło), adres buffer będzie nadal istniał, jednak w przypadku zamknięcia lub ponownego uruchomienia gry adres buffer zostanie utracony.
+UWAGA: Ponowne uruchomienie gry nie spowoduje wyczyszczenia ani usunięcia adresu buffer! Uniemożliwi jednak dalszy dostęp do wcześniej utworzonej strony buffer, ponieważ utracony zostanie uchwyt identyfikacyjny, co spowoduje wyciek pamięci, który w końcu doprowadzi do awarii gry. Dlatego przy ponownym uruchamianiu gry pamiętaj, aby najpierw usunąć wszystkie buffers.
+GameMaker pozwala na tworzenie czterech różnych typów buffer. Powodem tego jest fakt, że buffers został zaprojektowany jako wysoce zoptymalizowany tymczasowy nośnik danych i dlatego powinieneś utworzyć buffer odpowiedni do typu danych, które chcesz w nim przechowywać, w przeciwnym razie możesz otrzymać błędy lub spowodować wąskie gardło w swoim kodzie. Zanim wyjaśnimy to dalej, przyjrzyjmy się czterem dostępnym typom buffer (zdefiniowanym jako stałe w GML):
+
Constant | -description | +Stała | +opis |
---|---|---|---|
buffer_fixed | -- A buffer of a fixed size in bytes. The size is set when the buffer is created and cannot be changed again. |
+ buffer_fixed | ++ Adres buffer o stałym rozmiarze w bajtach. Rozmiar jest ustalany podczas tworzenia strony buffer i nie może być ponownie zmieniony. |
buffer_grow | -- A buffer that will grow dynamically as data is added. You create it with an initial size (which should be an approximation of the size of the data expected to be stored), and then it will expand to accept further data that overflows this initial size. |
+ buffer_grow | ++ Strona buffer, która będzie się dynamicznie powiększać w miarę dodawania danych. Tworzy się ją z rozmiarem początkowym (który powinien być przybliżony do rozmiaru danych, które mają być przechowywane), a następnie rozszerza się ją, aby przyjąć dalsze dane, które przekraczają ten rozmiar początkowy. |
buffer_wrap | -- A buffer where the data will wrap. When the data being added reaches the limit of the buffer size, the overwrite will be placed back at the start of the buffer, and further writing will continue from that point. |
+ buffer_wrap | ++ Adres buffer, na który będą zawijane dane. Gdy dodawane dane osiągną limit rozmiaru buffer, nadpisanie zostanie umieszczone z powrotem na początku buffer, a dalszy zapis będzie kontynuowany od tego miejsca. |
buffer_fast | -- This is a special "stripped down" buffer that is extremely fast to read/write to. However it can only be used with buffer_u8 data types, and must be 1 byte aligned. (Information on data types and byte alignment can be found further down this page). |
+ buffer_fast | ++ Jest to specjalny, "okrojony" adres buffer, na którym można bardzo szybko odczytywać i zapisywać dane. Można go jednak używać tylko z typami danych buffer_u8 i musi być wyrównany do 1 bajta. (Informacje o typach danych i wyrównywaniu bajtów można znaleźć w dalszej części tej strony). |
-
Those are the buffer types available to you when using GameMaker, and which one you choose will greatly depend on the use you wish to put it to. For example, a grow buffer would be used for storing a "snapshot" of data to create a save game since you do not know the actual amount of data that is going to be placed in it, or a fast buffer would be used when you know that the values you are working with are all between 0 and 255 or -128 and 127, for example when processing ARGB data from an image.
-When creating a buffer, you should always try to create it to a size that is appropriate to the type, with the general rule being that it should be created to accommodate the maximum size of data that it is to store, and if in doubt, use a grow buffer to prevent overwrite errors.
-The actual code to create a buffer would look something like this:
++
Są to typy buffer dostępne w programie GameMaker, a to, który z nich wybierzesz, zależy w dużej mierze od tego, do czego chcesz go wykorzystać. Na przykład strona grow buffer byłaby używana do przechowywania "migawek" danych w celu utworzenia zapisu gry, ponieważ nie znasz rzeczywistej ilości danych, które zostaną w niej umieszczone, lub szybka buffer byłaby używana, gdy wiesz, że wszystkie wartości, z którymi pracujesz, zawierają się w przedziale od 0 do 255 lub od -128 do 127, na przykład podczas przetwarzania danych ARGB z obrazu.
+Tworząc stronę buffer, należy zawsze starać się nadać jej rozmiar odpowiedni dla danego typu, przy czym ogólna zasada mówi, że powinna ona być utworzona tak, aby pomieścić maksymalny rozmiar danych, które ma przechowywać, a w razie wątpliwości należy użyć grow buffer, aby zapobiec błędom nadpisywania.
+Faktyczny kod tworzący stronę buffer wygląda mniej więcej tak:
player_buffer = buffer_create(16384, buffer_fixed, 2);
-
- That would create a fixed buffer of 16384 bytes and byte-aligned to 2, with the function returning a unique ID value that is stored in a variable for later referencing of this buffer.
When reading and writing data to a buffer, you do it in "chunks" of data defined by their "data type". The "data type" sets the number of bytes allocated within the buffer for the value being written, and it is essential that you get this correct otherwise you will get some very strange results (or even errors) for your code.
-Buffers are written to (and read from) sequentially, in that one piece of data is written after another, with each piece of data being of a set type. This means that you should ideally be aware of what data you are writing to the buffer at all times. These data types are defined in GML by the following constants:
-So, say you have created a buffer and you want to write information to it, then you would use something like the following code:
+
+ W ten sposób powstałaby stała strona buffer o rozmiarze 16384 bajtów i wyrównana do 2 bajtów. Funkcja zwróciłaby unikatową wartość identyfikacyjną, która jest przechowywana w zmiennej w celu późniejszego odwoływania się do tej strony buffer.
Podczas odczytywania i zapisywania danych na stronie buffer robi się to w "kawałkach" danych określonych przez ich "typ danych". Typ danych" określa liczbę bajtów przydzielonych w ramach buffer dla zapisywanej wartości i bardzo ważne jest, aby go poprawnie określić, w przeciwnym razie można uzyskać bardzo dziwne wyniki (lub nawet błędy) w swoim kodzie.
+Bufory są zapisywane (i odczytywane) sekwencyjnie, tzn. jedna porcja danych jest zapisywana po drugiej, a każda porcja danych jest określonego typu. Oznacza to, że użytkownik powinien zawsze wiedzieć, jakie dane zapisuje w buforze buffer. Te typy danych są zdefiniowane w witrynie GML za pomocą następujących stałych:
++
Typ danych Stała | +Bajty | +Opis | +
---|---|---|
buffer_u8 | +1 | ++ 8-bitowa liczba całkowita bez znaku. Jest to wartość dodatnia z zakresu od 0 do 255. |
+
buffer_s8 | +1 | ++ Podpisana, 8-bitowa liczba całkowita. Może to być wartość dodatnia lub ujemna z zakresu od -128 do 127 (0 jest wartością dodatnią). |
+
buffer_u16 | +2 | ++ Niepodpisana, 16-bitowa liczba całkowita. Jest to wartość dodatnia z zakresu od 0 do 65 535. |
+
buffer_s16 | +2 | ++ Podpisana, 16-bitowa liczba całkowita. Może to być wartość dodatnia lub ujemna z zakresu od -32,768 do 32,767 (0 oznacza wartość dodatnią). |
+
buffer_f16 | +2 | ++ 16-bitowa liczba zmiennoprzecinkowa. Może to być wartość dodatnia lub ujemna z zakresu +/- 65504. (Obecnie nieobsługiwana!) |
+
buffer_u32 | +4 | ++ Niepodpisana, 32-bitowa liczba całkowita. Jest to wartość dodatnia z zakresu od 0 do 4 294 967 295. |
+
buffer_s32 | +4 | ++ Podpisana, 32-bitowa liczba całkowita. Może to być wartość dodatnia lub ujemna z zakresu od -2,147,483,648 do 2,147,483,647 (0 oznacza wartość dodatnią). |
+
buffer_f32 | +4 | ++ 32-bitowa liczba zmiennoprzecinkowa. Może to być wartość dodatnia lub ujemna z zakresu +/-16777216. |
+
buffer_u64 | +8 | ++ 64-bitowa liczba całkowita bez znaku.(Obecnie nie jest obsługiwana przez wszystkie funkcje buffer!) |
+
buffer_f64 | +8 | ++ 64-bitowa liczba zmiennoprzecinkowa. |
+
buffer_bool | +1 | ++ Wartość logiczna. Może wynosić tylko 1 lub 0 (true lub false). |
+
buffer_string | +N/A | ++ Jest to plik UTF-8 zakończony zerem (0x00) string. Zasadniczo adres GameMaker string jest umieszczany w adresie buffer, a na końcu jest umieszczane 0. |
+
+
Jeśli więc utworzyłeś stronę buffer i chcesz zapisywać na niej informacje, użyj następującego kodu:
buffer_write(buff, buffer_bool, global.Sound);
buffer_write(buff, buffer_bool, global.Music);
buffer_write(buff, buffer_s16, obj_Player.x);
buffer_write(buff, buffer_s16, obj_Player.y);
buffer_write(buff, buffer_string, global.Player_Name);
looking at the example above you can see that you can write different types of data to a buffer at the same time (you are only limited to a specific data type when using the fast buffer type), and this data will be added into the buffer sequentially (although its actual position in the buffer will depend on its byte-alignment, explained below). This is the same for reading information from the buffer too, and in the case of the example given above, you would read from the buffer in the same order that you wrote the data, checking for the same data type, eg:
+Patrząc na powyższy przykład, widać, że można zapisywać różne typy danych na stronie buffer w tym samym czasie (w przypadku korzystania z szybkiego bufora jesteśmy ograniczeni tylko do jednego typu danych), a dane te będą kolejno dodawane do strony buffer (choć ich faktyczna pozycja w buffer będzie zależała od wyrównania bajtów, co wyjaśniono poniżej). Tak samo jest w przypadku odczytywania informacji z buffer. W powyższym przykładzie dane z buffer należy odczytywać w takiej samej kolejności, w jakiej zostały zapisane, sprawdzając, czy dane są tego samego typu, np:
global.Sound = buffer_read(buff, buffer_bool);
global.Music = buffer_read(buff, buffer_bool);
obj_Player.x = buffer_read(buff, buffer_s16);
obj_Player.y = buffer_read(buff, buffer_s16);
global.Player_Name = buffer_read(buff, buffer_string);
As you can see, you read out information in the same order that you read it into the buffer. For further information on how to add and remove data from the buffer please see the examples given below.
-If you have been reading through this page you will have seen references to the byte-alignment of a buffer. This basically refers to the position that new data will stored at within a given buffer. How does this work? Well, for a single byte aligned buffer, each piece of data is written to the buffer sequentially, with each new data piece being added directly after the previous. However a 2 byte aligned buffer will write each piece of data to intervals of 2 bytes, so that even if your initial write is 1 byte of data, the next write will be moved to align to two bytes:
-So, if your byte-alignment is set to, say, 4 bytes and you write a single piece of data which is 1 byte in size then do a buffer tell (a tell gets the current position for reading/writing for the buffer), you'll get an offset of 1 byte (the offset in this case is the number of bytes from the start of the buffer to the current read/write position).
-However, if you write another piece of data, also 1 byte in size, then do a buffer tell, you'll get an offset of 5 bytes (even though you have only written 2 bytes of data) as the alignment has padded the data to align it with the 4 byte buffer alignment.
-Basically, what this means is that alignment will only affect where things are written to, so if you do a buffer tell after you write something, it'll return the current write position which immediately follows the data you've previously written. Note, however, that if you then write another piece of data, internally the buffer will move the write position along to the next multiple of the alignment size before actually writing the piece of data.
-Below we have a couple of examples of how to use buffers in a project:
- +Jak widać, informacje są odczytywane w takiej samej kolejności, w jakiej zostały wczytane do buffer. Więcej informacji na temat dodawania i usuwania danych z buffer można znaleźć w poniższych przykładach.
+Jeśli czytałeś tę stronę, na pewno widziałeś wzmianki o wyrównaniu bajtów w adresie buffer. Odnosi się to do pozycji, na której nowe dane będą zapisywane w danym adresie buffer. Jak to działa? Otóż w przypadku strony buffer z wyrównaniem do jednego bajtu każda porcja danych jest zapisywana na stronie buffer kolejno, przy czym każda nowa porcja danych jest dodawana bezpośrednio po poprzedniej. Natomiast w przypadku strony buffer z wyrównaniem do 2 bajtów każdy fragment danych będzie zapisywany w odstępach 2-bajtowych, więc nawet jeśli początkowy zapis wyniesie 1 bajt danych, następny zapis zostanie wyrównany do dwóch bajtów:
+Jeśli więc wyrównanie bajtowe jest ustawione na, powiedzmy, 4 bajty i zapiszesz pojedynczy fragment danych o rozmiarze 1 bajta, a następnie wykonasz tell buffer (tell określa bieżącą pozycję do odczytu/zapisu dla buffer), otrzymasz przesunięcie o 1 bajt (przesunięcie w tym przypadku to liczba bajtów od początku adresu buffer do bieżącej pozycji odczytu/zapisu).
+Jeśli jednak zapiszesz kolejną porcję danych, również o rozmiarze 1 bajta, a następnie wykonasz buffer tell, otrzymasz przesunięcie o 5 bajtów (mimo że zapisałeś tylko 2 bajty danych), ponieważ wyrównanie spowodowało wyścielenie danych, aby wyrównać je do 4-bajtowego wyrównania buffer.
+Zasadniczo oznacza to, że wyrównanie będzie miało wpływ tylko na miejsce zapisu, więc jeśli wykonasz buffer tell po zapisaniu czegoś, zwróci ono bieżącą pozycję zapisu, która znajduje się bezpośrednio za wcześniej zapisanymi danymi. Zauważ jednak, że jeśli następnie napiszesz kolejną porcję danych, to buffer wewnętrznie przesunie pozycję zapisu do następnej wielokrotności rozmiaru wyrównania przed faktycznym zapisem porcji danych.
+Poniżej przedstawiamy kilka przykładów wykorzystania strony buffers w projekcie:
++
A simple example of how a buffer can be used in any GameMaker game for any platform, is the function game_save_buffer(). This function will take a "snapshot" of the current game state and save it to a pre-defined buffer, which can then be read from to load the game at that point again.
-This function is very limited and it is designed for the beginner to get a checkpoint system up and running quickly, but more advanced users may prefer to code their own system using the File functions, due to the fact that the game will not save any of the dynamic resources that you can create at run-time like data structures, surfaces, added sprites, etc...
-The first thing we need to do is create a new object to control the saving and loading, so you would make one and give it a Create Event. In this event, you could place the following code:
+Prostym przykładem na to, jak można wykorzystać stronę buffer w dowolnej grze GameMaker na dowolną platformę, jest funkcja game_save_buffer(). Funkcja ta wykonuje "migawkę" bieżącego stanu gry i zapisuje ją w zdefiniowanym wcześniej adresie buffer, który można następnie odczytać, aby ponownie załadować grę w tym samym punkcie.
+UWAGA: Ta funkcja jest bardzo ograniczona i została zaprojektowana dla początkujących graczy, aby szybko uruchomić system punktów kontrolnych. Bardziej zaawansowani użytkownicy mogą jednak preferować kodowanie własnego systemu przy użyciu funkcji pliku, ponieważ gra nie zapisze żadnych zasobów dynamicznych, które można utworzyć w czasie gry, takich jak struktury danych, powierzchnie, dodane strony sprites, itp.
+Pierwszą rzeczą, którą musimy zrobić, jest utworzenie nowego adresu object, który będzie sterował zapisywaniem i ładowaniem danych, dlatego należy go utworzyć i nadać mu zdarzenie Create. W tym zdarzeniu można umieścić następujący kod:
SaveBuffer = buffer_create(1024, buffer_grow, 1);
StateSaved = false;
The first line creates a grow buffer (since we don't know the final size of the saved data) of 1024 bytes and aligned to 1 byte. A variable is then created to check against and see if the game has been saved or not (this will be used for loading).
-Next we would add a Keypress Event (for example) in which we will save the current game state to the created buffer:
+W pierwszym wierszu tworzony jest plik grow buffer (ponieważ nie znamy ostatecznego rozmiaru zapisanych danych) o rozmiarze 1024 bajtów i wyrównany do 1 bajta. Następnie tworzona jest zmienna, która będzie sprawdzać, czy gra została zapisana, czy nie (zostanie ona użyta podczas wczytywania).
+Następnie dodajemy zdarzenie naciśnięcia klawisza (na przykład), w którym zapiszemy bieżący stan gry do utworzonego bufora:
StateSaved = true;
buffer_seek(SaveBuffer, buffer_seek_start, 0);
game_save_buffer(SaveBuffer);
The above will first set the control variable to true (so that this is saved when we save the game to the buffer) and then seek to the start of the buffer before writing the current save state into it. Why do we use buffer_seek()? Well, as mentioned already on this page, you read and write to a buffer from the last position that data was added to it. This means that if you don't set the buffer tell back to the start then when you save you will be adding the data into the buffer at the current buffer read/write position. So, we use the function buffer_seek() to move the tell to the buffer start.
-We have now saved the current game state to a buffer. The next step would be to code how to load it, probably in another Keypress Event:
+Powyższe działanie spowoduje najpierw ustawienie zmiennej sterującej na true (dzięki czemu zostanie ona zapisana podczas zapisywania gry na stronie buffer), a następnie przejście na początek strony buffer przed zapisaniem do niej bieżącego stanu zapisu. Dlaczego używamy buffer_seek()? Otóż, jak już wspomniano na tej stronie, czytasz i zapisujesz na stronie buffer od miejsca, w którym ostatnio zostały do niej dodane dane. Oznacza to, że jeśli nie ustawisz buffer tell z powrotem na początek, to podczas zapisywania dane zostaną dodane do buffer w bieżącej pozycji odczytu/zapisu buffer. Dlatego użyjemy funkcji buffer_seek(), aby przenieść tell na początek buffer.
+Aktualny stan gry został zapisany na stronie buffer. Następnym krokiem będzie zakodowanie sposobu jego załadowania, prawdopodobnie w innym zdarzeniu Keypress Event:
if StateSaved
{
buffer_seek(SaveBuffer, buffer_seek_start, 0);
game_load_buffer(SaveBuffer);
}
The game will then be loaded at the end of the event in which you place the above code.
-This is only for use in the same room, and not for generating complete saved games for after your game has been closed or restarted!
-The final thing to add to the controller object is some "clean up" code. Buffers are stored in memory and as such if you do not clean up when you are finished with them, you can get memory leaks that will eventually lag and crash your game. So you would probably add a Room End Event (from the Other event category) with:
+Gra zostanie załadowana na końcu zdarzenia, w którym umieszczono powyższy kod.
+UWAGA: Można tego używać tylko w tej samej witrynie room, a nie do generowania kompletnych zapisanych gier po zamknięciu lub ponownym uruchomieniu gry!
+Ostatnią rzeczą, którą należy dodać do kontrolera object, jest kod "czyszczący". Buffers są przechowywane w pamięci i jeśli nie wyczyścisz ich po zakończeniu, mogą wystąpić wycieki pamięci, które w końcu spowodują lagi i awarię gry. Można więc dodać zdarzenie zakończenia pomieszczenia (z kategorii Inne zdarzenia ) o treści:
buffer_delete(SaveBuffer);
-This object can now be placed into a room and on a key press save and load the room state from a buffer.
-+
Tę stronę object można teraz umieścić w witrynie room, a po naciśnięciu klawisza zapisać i załadować stan room z witryny buffer.
+
When working with the GameMaker networking functions, you have to use buffers to create the data packet that is being sent over the network connection. This example intends to show how this is done, but due to the scope of the networking possibilities, it is only designed to show how to use the buffers themselves, and not the full networking system.
-The first thing we will show is the creation and use of a buffer for the client side of the network connection. This buffer will be used to create small data packets that can then be sent to the server, so in the Create Event of an instance we would assign a buffer like this:
+Podczas pracy z funkcjami sieciowymi programu GameMaker należy używać adresu buffers do tworzenia pakietów danych, które są przesyłane przez połączenie sieciowe. Ten przykład ma na celu pokazanie, jak to się robi, ale ze względu na zakres możliwości sieciowych ma on na celu jedynie pokazanie, jak używać samego buffers, a nie całego systemu sieciowego.
+Pierwszą rzeczą, którą pokażemy, jest tworzenie i używanie buffer po stronie klienta połączenia sieciowego. Ta strona buffer będzie używana do tworzenia małych pakietów danych, które następnie będą mogły być wysyłane do strony server, dlatego w zdarzeniu tworzenia instancji przypisalibyśmy jej adres buffer w następujący sposób:
send_buff = buffer_create(256, buffer_grow, 1);
-We make the buffer small (256 bytes) - as it is not intended for holding large amounts of data - then we make it a grow buffer to ensure no errors should we need to add more data to be sent at any time, and the alignment is set to one for convenience.
-Now, let's say that we want our client to send data to the server. For that we need to create a buffer "packet", and in this example we are going to send a Key Press Event, like when the player presses Left Arrow to move around the game. To do this we write the necessary data to the buffer first then send it off:
+Strona buffer jest niewielka (256 bajtów), ponieważ nie jest przeznaczona do przechowywania dużych ilości danych, a następnie jest powiększana (grow buffer ), aby zapewnić brak błędów w przypadku konieczności dodania większej ilości danych do wysłania w dowolnym momencie, a wyrównanie jest ustawione na jeden dla wygody.
+Załóżmy, że chcemy, aby nasz klient wysyłał dane do server. W tym celu musimy utworzyć "pakiet" buffer. W tym przykładzie wyślemy zdarzenie naciśnięcia klawisza, np. gdy gracz naciśnie strzałkę w lewo , aby poruszać się w grze. Aby to zrobić, najpierw zapisujemy niezbędne dane na stronie buffer, a następnie je wysyłamy:
buffer_seek(buff, buffer_seek_start, 0);
buffer_write(buff, buffer_u8, 1);
buffer_write(buff, buffer_s16, vk_left);
buffer_write(buff, buffer_bool, true);
network_send_packet(client, buff, buffer_tell(buff));
Before writing to the buffer we have set the "tell" to the start of the buffer as networking always takes the data from the start of a buffer. We then write the check value (this will be used by the server to determine the type of event to be processed), then the key being used, and then the state of the key (in this case true for pressed). This buffer is then sent as a data packet by the network function. Note that we do not send the whole buffer! We only send the data written, using the buffer_tell function to return the current read/write position of the buffer (remember that writing to the buffer moves the "tell" to the end of what has been written). This is simply to avoid sending more bytes than is necessary.
-What about receiving the data on the server? The received data packet that must be written into the buffer on the server and then used to update the game. For that we would use the Networking Asynchronous Event in the network controller object of the server, as this simplified code below shows:
+Przed zapisem na stronie buffer ustawiamy "tell" na początek strony buffer, ponieważ sieci zawsze pobierają dane od początku strony buffer. Następnie wpisujemy wartość kontrolną (zostanie ona wykorzystana przez stronę server do określenia typu zdarzenia, które ma zostać przetworzone), używany klawisz, a następnie stan klawisza (w tym przypadku true oznacza naciśnięty). Ta strona buffer jest następnie wysyłana przez funkcję sieciową jako pakiet danych. Zwróć uwagę, że nie wysyłamy całej strony buffer! Wysyłamy tylko zapisane dane, używając funkcji buffer_tell do zwrócenia aktualnej pozycji odczytu/zapisu na stronie buffer (pamiętaj, że zapis na stronie buffer przenosi "tell" na koniec tego, co zostało zapisane). Ma to na celu uniknięcie wysyłania większej liczby bajtów, niż jest to konieczne.
+A co z odbiorem danych na stronie server? Odebrany pakiet danych musi zostać zapisany w buffer na stronie server, a następnie wykorzystany do aktualizacji gry. W tym celu należy użyć zdarzenia asynchronicznego Networking w kontrolerze sieciowym object na stronie server, jak pokazano w poniższym uproszczonym kodzie:
var buff = ds_map_find_value(async_load, "buffer");
if cmd == buffer_read(buff, buffer_u8);
{
key = buffer_read(buff, buffer_s16);
key_state = buffer_read(buff, buffer_bool);
}
The asynchronous event will contain a special temporary DS map async_load (it is removed from memory at the end of the event automatically) which contains different information depending on the type of incoming data from the network. In this case, we are assuming that the map has been checked and found to be a buffer data packet sent from a client. We now check the first piece of data that is in the buffer to see what kind of event has been sent - in this case the value "1" represents a key event, however when coding these things you should define constants to hold these values to simplify things - and then store the key being pressed and its state (true = pressed, false = released). This information would then be used to update all the clients with the new status of the sending client player.
-The buffer that is created from the DS map is automatically removed at the end of the Network Asynchronous Event so there is no need to use buffer_delete() here.
-+
Zdarzenie asynchroniczne będzie zawierało specjalną tymczasową mapę DS async_load (jest ona usuwana z pamięci po zakończeniu zdarzenia automatycznie), która zawiera różne informacje w zależności od typu danych przychodzących z sieci. W tym przypadku zakładamy, że mapa została sprawdzona i uznana za pakiet danych buffer wysłany od klienta. Sprawdzamy teraz pierwszą część danych, która znajduje się na stronie buffer, aby sprawdzić, jakiego rodzaju zdarzenie zostało wysłane - w tym przypadku wartość "1" oznacza zdarzenie związane z klawiszem, jednak podczas kodowania takich rzeczy należy zdefiniować stałe przechowujące te wartości, aby uprościć pracę - a następnie zapisujemy naciśnięty klawisz i jego stan (true = naciśnięty, false = zwolniony). Te informacje zostaną następnie użyte do zaktualizowania wszystkich klientów o nowy stan gracza wysyłającego.
+UWAGA: Strona buffer utworzona z mapy DS jest automatycznie usuwana na końcu zdarzenia asynchronicznego sieci, więc nie ma potrzeby używania tutaj funkcji buffer_delete().
+
-
-
+
+
+
-
This guide is for those of you who want to understand how to use and create particles in GML. This page will cover both the GML Code functions and GML Visual actions for particles, so if you've never used particles before, we hope that this guide can get you started as they are very useful and quite fun to make.
-Before going any further, we should probably explain what a particle actually is... Basically, a particle is a graphic resource that has certain properties which are defined by a particle system. These properties cannot be manipulated directly for individual particles, but are changed collectively through the code or actions that are used to define the system that it belongs to. They are very useful for creating beautiful and flashy effects - or subtle and discreet ones - in a game without the CPU overhead that using instances has.
-We have mentioned particle systems, so let's explain what that is before continuing. Think of a particle system like a container that you will use to hold your particles ready for use. You can use code or actions to define the visual aspect of the particles, and then they are placed in the "container" (the particle system) so that you can take it out and use it whenever and wherever you need it later.
-Before setting up a system and creating particles, it's important to know a few things... First is that most of a particle systems code is only ever called once in the game, usually in some type of controller object in the first room or level - this is not always the case, but for the sake of simplicity, we'll be using this scenario for the following brief guide as it's the most common way to use particles. You do this because a particle system, once created, stays in memory and is ready to be used at any time, so if you create it more than once it can quickly increase the memory usage and cause serious lag, and even has the potential of crashing the game. For the sake of simplicity in this guide, you will make a global particle system that can be used by any instance in the game at any time.
-- -
To start with you need to define the particle system and give it a name so that you can use it. As this is going to be a global system that any object can use you would do this in a controller object or an initialisation function run at the start of the game. The GML Code would look like this:
-global.P_System = part_system_create_layer("Instance_Layer", false);
-And using GML Visual:
- -The layer name supplied must be a valid layer in the room where the system will be used, otherwise no particles will be visible. Also note that we set the persistent flag (both in code and in GML Visual) to false. A persistent particle system is one that will "persist" across rooms without the need to destroy and re-create it for each room. However, to keep things simple for this guide, we'll not be using persistence.
-So that's the system created, but what about the particles? We have to define them too or the system is useless and does nothing.
-If you already have a Particle System Asset, you can create it using the above function/action by passing the asset into the partsys/"System" argument.
--
To use a particle in a system you have to first define its general properties. These are like object properties, but they only apply in a general way to individual particles. What this means is that if you give the particles a minimum movement speed of 1 and a maximum movement speed of 2, any particle created by the system will have a random speed between 1 and 2 pixels per step, and that overall they will have an average speed of 1.5. You should name and add your first particle to the system using the following GML in the same object that you used to create the system:
-global.Particle1 = part_type_create();
-And for those of you that use GML Visual:
- -Using GML Visual we also tick the blend option. This enables additive blending for the particle, which we'll discuss a bit further down.
-You now have a system and a particle to put in it, but you're not ready yet to create your outstanding effects! You still have to define the properties of the particle, ie: how it looks - its speed, its rotation, its alpha, etc. There are a lot of details that can be used to define a particle effect, so below is an overview of the most important settings and then a snippet of code and GML Visual that uses all of them:
-Now, before we present you the code for defining the particle, let's just talk about "wiggle" for a moment... Believe it or not, "wiggle" is a particle property and can be set for many of the above settings individually. When you see "wiggle" as an argument for a particle function or action, it means that if you place a number between 1 and 20 the particle will "wiggle" or fluctuate between the min and max values for the property, with 1 being a slow wiggle and 20 being very fast. So a particle speed minimum of 2 and maximum of 5 with a wiggle of 20 will oscillate very quickly between the min/max speeds for the lifetime of each particle created.
-There are other minor particle properties too which we don't cover here, just to keep things as simple as possible to start with. See the appropriate pages for full details of particle properties.
-Let's look at some code that defines a particle now:
-// This defines the particle's shape
- part_type_shape(global.Particle1,pt_shape_pixel);
-
- // This is for the size
- part_type_size(global.Particle1,1,1,0,2);
-
- // This sets its colour. There are three different codes for this
- part_type_color1(global.Particle1,c_white);
-
- // This is its alpha. There are three different codes for this
- part_type_alpha1(global.Particle1,1);
-
- // The particles speed
- part_type_speed(global.Particle1,0.50,2,-0.10,0);
-
- // The direction
- part_type_direction(global.Particle1,0,359,0,20);
-
- // This changes the rotation of the particle
- part_type_orientation(global.Particle1,0,0,0,0,true);
-
- // This is the blend mode, either additive or normal
- part_type_blend(global.Particle1,1);
-
- // This is its lifespan in steps
- part_type_life(global.Particle1,5,30);
-
To create this same particle definition in GML Visual we'd need these actions:
-So that's it! We have now defined our particles and they are ready to be used.
--
Creating Particles Directly In-Game
-There are a couple of ways to create particles, and each has its pros and cons. You can use emitters to burst or stream particles, or you can create particles directly at a point. Which one you use really depends on what you are trying to achieve and the effect you are wanting to create, but we'll start with the easiest of the two, which is creating particles directly. In GML we'd use the following function:
-part_particles_create(global.P_System, x, y, global.Particle1, 10);
-and in GML Visual it'd be:
-That single code/action above will create 10 particles at the given x/y coordinates of type "Particle1" from our global system. Simple! The great thing about that line of code/action is that it can be used anywhere without any fuss. For example if you place it in the Global Left Pressed event for the mouse in an object and change x/y values for the mouse_x/y position, it will create particles at the mouse position every time you press the button. Or if you have a rocket, then you could place this in the step event and have smoke particles coming every step (although 1 or 2 would probably be better than 10!). You can even have it create particles over an area by changing the x/y coordinates randomly, for example:
-repeat(50)
- {
- var xx = x + 20 - random(40);
- var yy = y + 20 - random(40);
- part_particles_create(global.P_System, xx, yy, global.Particle1, 1);
- }
The above code will create 50 particles at a random position within a 40px square area.
--
Creating Particles With Emitters
-Since we've explained the easy way to create particles, let's now go the slightly more complex way, which is to use emitters. Emitters are another part of the particle system that has to be defined before being used, so we'll make a global emitter the same as we did for the system and the particles. We also have to decide whether to have a static (non-moving) emitter or not and whether we are going to burst or stream the particles, as well as decide over what area and what kind of distribution we are going to have the emitter use.
-What does all that mean? Well, a static emitter is one that you can define once and forget about as it will not be moving anywhere for the duration of the game, ie: think of a log fire - it doesn't move, it just emits flames and so is static, but a fireball would require a dynamic emitter and will move across the screen. As for bursting or streaming, a burst is a one off explosion of particles, whereas a stream is just that - a constant stream of particles every step. For area and distribution, with emitters you can define an area for emitting particles (which can be a rectangle, ellipse, diamond or line) as well as the distribution curve (gaussian, inverse gaussian, or linear).
-The following images illustrate the different types of area shape available for emitters:
--
- And the distribution curves (linear, gaussian, and inverse gaussian) are illustrated here:
Below is an example of the code/actions required to define two emitters, which would normally go in the Create Event of a controller object, just after defining the particle system. One will be static and stream particles over the area of the whole room, while the other will be dynamic and follow the mouse and burst every 30 steps from a small ellipse:
--
global.Particle1_Emitter1 = part_emitter_create(global.P_System);
- global.Particle1_Emitter2 = part_emitter_create(global.P_System);
-
- // Set up the area that will emit particles
- part_emitter_region(global.P_System, global.Particle1_Emitter1, 0, room_width, 0, room_height, ps_shape_rectangle, ps_distr_linear);
- part_emitter_region(global.P_System, global.Particle1_Emitter2, mouse_x-10, mouse_x+10, mouse_y-10, mouse_y+10, ps_shape_ellipse, ps_distr_gaussian);
-
- // Set the first to stream 10 particles every step
- part_emitter_stream(global.P_System, global.Particle1_Emitter1, global.Particle1, 10);
-
- // This can now be forgotten as it will function until told to stop...
- // Set the alarm[0] event to burst the emitter2 particles...
- alarm[0] = 30;
-
So, here we are creating two particle emitters that are assigned to the particle system we created at the start. The functions/actions to create these emitters permit us to define an area in the room over which they will emit particles, as well as give the particle type to emit, and the shape and distribution to use within the defined area. The functions/actions will return a numeric value, which is the emitter ID value, and we store this in a variable so that we can use further emitter functions to target those emitters.
-Now we have code/GML Visual to stream particles (these particles will be emitted every game step without us having to anything else), but we also want to add an Alarm[0] Event to burst particles at specific intervals:
-part_emitter_region(global.P_System, global.Particle1_Emitter2, mouse_x - 10, mouse_x + 10, mouse_y - 10, mouse_y + 10, ps_shape_ellipse, ps_distr_gaussian);
- part_emitter_burst(global.P_System, global.Particle1_Emitter2, global.Particle1, 30);
- alarm[0] = 30;
A particle burst is simply a one-off explosion of particles from the emitter, rather than a constant stream of them every game step.
-But what if you want several objects to emit particles? A global emitter can only be in one place at a time, so you would need to create local emitters in each object. These emitters will still use the global particle system and any particles that are within it, but they can be different shapes and sizes and move with the object, making them ideal for rockets or bullets or things. The code you would use is exactly the same as above, but without the "global" prefix before the emitter names.
-That's the creation of particles dealt with but there is one more thing that's very important... Cleaning up when you are finished with them.
--
As mentioned at the start, once created, a particle system (and its particles, emitters, etc.) are stored in memory for instant use. Great, but what happens when you restart the game? Or if your player dies and starts the room again? Well, if you don't manage the game right you get a memory leak. This is when something has been created and uses up memory, but has been "de-referenced" meaning that GameMaker no longer has access to it. This kind of thing will slowly eat up memory and cause lag in your game or even block the computer causing your game to crash, and it is a pretty common problem with first time users of particle systems.
-How do you avoid this? Well, GameMaker has GML Code functions and GML Visual actions to delete particle systems and their emitters and particles from memory when not in use, and with a little bit of planning when using the following code/actions, you can easily prevent this potential problem.
-The first thing you have to do is decide where you are going to create the system and how you will use it. You could create a global system in the Game Start Event of an object that is in your first room (like a menu or title screen), but this means that if you restart the game using the game_restart function, it will be recreated and cause a memory leak. Or you could create a local system in an instance in any room, but again, if you leave the room then the system will be inaccessible and cause a memory leak. To avoid this you would need to have something like this in the Game End Event or the Clean Up Event of your object:
-part_type_destroy(global.Particle1);
- part_emitter_destroy(global.P_System, global.Particle1_Emitter);
- part_emitter_destroy(global.P_System, global.Particle2_Emitter);
- part_system_destroy(global.P_System);
This will remove the defined particles, emitters, and then the system from memory ready for you to restart the game or change room. Just remember that after thinking about where would be the most suitable place to create the system, think about where would be the most suitable place to destroy the system too!
--
-
Now you know the basics about particles, particle systems and emitters, so you can now add them into your game! But before rushing off and adding particle effects to everything, please note that while particles are less CPU hungry than instances, they are not the solution to everything as they will cause lag if you have thousands of them at a time. The best thing to do is experiment and use them carefully to "flesh out" visually a game and give it a bit more eye-candy without over doing it.
--
-