cfsa-antigravity 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,1032 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: godot
|
|
3
|
+
description: "Comprehensive Godot 4.x game development guide covering scene tree architecture, GDScript patterns (signals, exports, @onready), physics systems (CharacterBody2D/3D, RigidBody, Area), input mapping, resource system, autoload singletons, animation, tilemaps, UI system, multiplayer, audio, particles, shaders, GDExtension, export presets, and debugging tools. Use when building games with Godot Engine."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Godot 4.x Game Development
|
|
8
|
+
|
|
9
|
+
## 1. Scene Tree Architecture
|
|
10
|
+
|
|
11
|
+
### Node Hierarchy
|
|
12
|
+
|
|
13
|
+
Every Godot game is a tree of nodes. Scenes are reusable branches of that tree.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Game (Node)
|
|
17
|
+
+-- World (Node2D)
|
|
18
|
+
| +-- Player (CharacterBody2D)
|
|
19
|
+
| | +-- Sprite (Sprite2D)
|
|
20
|
+
| | +-- Collision (CollisionShape2D)
|
|
21
|
+
| | +-- Camera (Camera2D)
|
|
22
|
+
| +-- Enemies (Node2D)
|
|
23
|
+
| | +-- Goblin (CharacterBody2D)
|
|
24
|
+
| +-- TileMap (TileMapLayer)
|
|
25
|
+
+-- UI (CanvasLayer)
|
|
26
|
+
+-- HUD (Control)
|
|
27
|
+
+-- PauseMenu (Control)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Scene Composition
|
|
31
|
+
|
|
32
|
+
Scenes are the primary unit of reuse. Each scene is a `.tscn` file.
|
|
33
|
+
|
|
34
|
+
```gdscript
|
|
35
|
+
# Instantiate a scene at runtime
|
|
36
|
+
var enemy_scene: PackedScene = preload("res://scenes/enemies/goblin.tscn")
|
|
37
|
+
|
|
38
|
+
func spawn_enemy(position: Vector2) -> void:
|
|
39
|
+
var enemy: CharacterBody2D = enemy_scene.instantiate()
|
|
40
|
+
enemy.global_position = position
|
|
41
|
+
$Enemies.add_child(enemy)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Scene Ownership Rules
|
|
45
|
+
|
|
46
|
+
- The root node of a scene owns all its children.
|
|
47
|
+
- Nodes added at runtime via `add_child()` are not saved with the scene unless `owner` is set.
|
|
48
|
+
- Use `queue_free()` to safely remove nodes (deferred to end of frame).
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 2. GDScript Patterns
|
|
53
|
+
|
|
54
|
+
### Exports and @onready
|
|
55
|
+
|
|
56
|
+
```gdscript
|
|
57
|
+
class_name Player
|
|
58
|
+
extends CharacterBody2D
|
|
59
|
+
|
|
60
|
+
# Exported variables appear in the Inspector
|
|
61
|
+
@export var speed: float = 200.0
|
|
62
|
+
@export var jump_force: float = -400.0
|
|
63
|
+
@export_range(0.0, 1.0, 0.05) var friction: float = 0.1
|
|
64
|
+
@export var projectile_scene: PackedScene
|
|
65
|
+
@export_enum("Warrior", "Mage", "Rogue") var player_class: int = 0
|
|
66
|
+
@export_group("Combat")
|
|
67
|
+
@export var max_health: int = 100
|
|
68
|
+
@export var attack_damage: int = 10
|
|
69
|
+
|
|
70
|
+
# @onready resolves node paths when the node enters the tree
|
|
71
|
+
@onready var sprite: Sprite2D = $Sprite2D
|
|
72
|
+
@onready var anim_player: AnimationPlayer = $AnimationPlayer
|
|
73
|
+
@onready var collision: CollisionShape2D = $CollisionShape2D
|
|
74
|
+
@onready var ray: RayCast2D = $RayCast2D
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Signals
|
|
78
|
+
|
|
79
|
+
```gdscript
|
|
80
|
+
# Define custom signals
|
|
81
|
+
signal health_changed(new_health: int, max_health: int)
|
|
82
|
+
signal died
|
|
83
|
+
signal item_collected(item_name: String)
|
|
84
|
+
|
|
85
|
+
# Emit signals
|
|
86
|
+
func take_damage(amount: int) -> void:
|
|
87
|
+
health -= amount
|
|
88
|
+
health_changed.emit(health, max_health)
|
|
89
|
+
if health <= 0:
|
|
90
|
+
died.emit()
|
|
91
|
+
|
|
92
|
+
# Connect signals in code
|
|
93
|
+
func _ready() -> void:
|
|
94
|
+
# Connect to own signal
|
|
95
|
+
health_changed.connect(_on_health_changed)
|
|
96
|
+
# Connect to child signal
|
|
97
|
+
$HitArea.body_entered.connect(_on_hit_area_body_entered)
|
|
98
|
+
|
|
99
|
+
func _on_health_changed(new_health: int, _max_health: int) -> void:
|
|
100
|
+
if new_health < 20:
|
|
101
|
+
sprite.modulate = Color.RED
|
|
102
|
+
|
|
103
|
+
func _on_hit_area_body_entered(body: Node2D) -> void:
|
|
104
|
+
if body.is_in_group("enemies"):
|
|
105
|
+
take_damage(body.attack_damage)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Type Hints and Static Typing
|
|
109
|
+
|
|
110
|
+
```gdscript
|
|
111
|
+
# Always use type hints for clarity and performance
|
|
112
|
+
var enemies: Array[CharacterBody2D] = []
|
|
113
|
+
var inventory: Dictionary = {}
|
|
114
|
+
|
|
115
|
+
func calculate_damage(base: int, multiplier: float) -> int:
|
|
116
|
+
return int(base * multiplier)
|
|
117
|
+
|
|
118
|
+
# Typed arrays
|
|
119
|
+
func get_nearby_enemies(radius: float) -> Array[Node2D]:
|
|
120
|
+
var result: Array[Node2D] = []
|
|
121
|
+
for enemy in get_tree().get_nodes_in_group("enemies"):
|
|
122
|
+
if global_position.distance_to(enemy.global_position) < radius:
|
|
123
|
+
result.append(enemy)
|
|
124
|
+
return result
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Lifecycle Methods
|
|
128
|
+
|
|
129
|
+
```gdscript
|
|
130
|
+
func _init() -> void:
|
|
131
|
+
# Called when object is created (before _ready)
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
func _ready() -> void:
|
|
135
|
+
# Called when node enters the scene tree (children are ready)
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
func _process(delta: float) -> void:
|
|
139
|
+
# Called every frame (variable timestep)
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
func _physics_process(delta: float) -> void:
|
|
143
|
+
# Called every physics tick (fixed timestep, default 60 Hz)
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
func _unhandled_input(event: InputEvent) -> void:
|
|
147
|
+
# Called for input not consumed by UI or _input
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
func _enter_tree() -> void:
|
|
151
|
+
# Called when node is added to tree (before _ready on first add)
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
func _exit_tree() -> void:
|
|
155
|
+
# Called when node is removed from tree
|
|
156
|
+
pass
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 3. Physics System
|
|
162
|
+
|
|
163
|
+
### CharacterBody2D (Platformer)
|
|
164
|
+
|
|
165
|
+
```gdscript
|
|
166
|
+
extends CharacterBody2D
|
|
167
|
+
|
|
168
|
+
@export var speed: float = 300.0
|
|
169
|
+
@export var jump_velocity: float = -400.0
|
|
170
|
+
@export var gravity_multiplier: float = 1.0
|
|
171
|
+
|
|
172
|
+
var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
|
|
173
|
+
|
|
174
|
+
func _physics_process(delta: float) -> void:
|
|
175
|
+
# Apply gravity
|
|
176
|
+
if not is_on_floor():
|
|
177
|
+
velocity.y += gravity * gravity_multiplier * delta
|
|
178
|
+
|
|
179
|
+
# Jump
|
|
180
|
+
if Input.is_action_just_pressed("jump") and is_on_floor():
|
|
181
|
+
velocity.y = jump_velocity
|
|
182
|
+
|
|
183
|
+
# Horizontal movement
|
|
184
|
+
var direction: float = Input.get_axis("move_left", "move_right")
|
|
185
|
+
if direction != 0.0:
|
|
186
|
+
velocity.x = direction * speed
|
|
187
|
+
else:
|
|
188
|
+
velocity.x = move_toward(velocity.x, 0.0, speed * 0.2)
|
|
189
|
+
|
|
190
|
+
move_and_slide()
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### CharacterBody3D (First Person)
|
|
194
|
+
|
|
195
|
+
```gdscript
|
|
196
|
+
extends CharacterBody3D
|
|
197
|
+
|
|
198
|
+
@export var speed: float = 5.0
|
|
199
|
+
@export var jump_velocity: float = 4.5
|
|
200
|
+
@export var mouse_sensitivity: float = 0.002
|
|
201
|
+
|
|
202
|
+
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
|
203
|
+
|
|
204
|
+
func _ready() -> void:
|
|
205
|
+
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
206
|
+
|
|
207
|
+
func _unhandled_input(event: InputEvent) -> void:
|
|
208
|
+
if event is InputEventMouseMotion:
|
|
209
|
+
rotate_y(-event.relative.x * mouse_sensitivity)
|
|
210
|
+
$Camera3D.rotate_x(-event.relative.y * mouse_sensitivity)
|
|
211
|
+
$Camera3D.rotation.x = clampf($Camera3D.rotation.x, -PI / 2, PI / 2)
|
|
212
|
+
|
|
213
|
+
func _physics_process(delta: float) -> void:
|
|
214
|
+
if not is_on_floor():
|
|
215
|
+
velocity.y -= gravity * delta
|
|
216
|
+
if Input.is_action_just_pressed("jump") and is_on_floor():
|
|
217
|
+
velocity.y = jump_velocity
|
|
218
|
+
|
|
219
|
+
var input_dir: Vector2 = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
|
220
|
+
var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
|
221
|
+
if direction != Vector3.ZERO:
|
|
222
|
+
velocity.x = direction.x * speed
|
|
223
|
+
velocity.z = direction.z * speed
|
|
224
|
+
else:
|
|
225
|
+
velocity.x = move_toward(velocity.x, 0.0, speed)
|
|
226
|
+
velocity.z = move_toward(velocity.z, 0.0, speed)
|
|
227
|
+
|
|
228
|
+
move_and_slide()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### RigidBody2D
|
|
232
|
+
|
|
233
|
+
```gdscript
|
|
234
|
+
extends RigidBody2D
|
|
235
|
+
|
|
236
|
+
@export var explosion_force: float = 500.0
|
|
237
|
+
|
|
238
|
+
func _ready() -> void:
|
|
239
|
+
# RigidBody properties
|
|
240
|
+
mass = 2.0
|
|
241
|
+
gravity_scale = 1.0
|
|
242
|
+
linear_damp = 0.5
|
|
243
|
+
angular_damp = 1.0
|
|
244
|
+
# Collision layers
|
|
245
|
+
collision_layer = 2 # What layer this body is ON
|
|
246
|
+
collision_mask = 1 # What layers this body DETECTS
|
|
247
|
+
|
|
248
|
+
func explode(origin: Vector2) -> void:
|
|
249
|
+
var direction: Vector2 = (global_position - origin).normalized()
|
|
250
|
+
apply_impulse(direction * explosion_force)
|
|
251
|
+
|
|
252
|
+
func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
|
|
253
|
+
# Low-level physics override (runs in physics step)
|
|
254
|
+
if state.get_contact_count() > 0:
|
|
255
|
+
var contact_body: Node = state.get_contact_collider_object(0)
|
|
256
|
+
if contact_body.is_in_group("lava"):
|
|
257
|
+
queue_free()
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Area2D for Detection
|
|
261
|
+
|
|
262
|
+
```gdscript
|
|
263
|
+
extends Area2D
|
|
264
|
+
|
|
265
|
+
signal player_entered
|
|
266
|
+
signal player_exited
|
|
267
|
+
|
|
268
|
+
func _ready() -> void:
|
|
269
|
+
body_entered.connect(_on_body_entered)
|
|
270
|
+
body_exited.connect(_on_body_exited)
|
|
271
|
+
# Monitoring detects other bodies; monitorable makes it detectable
|
|
272
|
+
monitoring = true
|
|
273
|
+
monitorable = true
|
|
274
|
+
|
|
275
|
+
func _on_body_entered(body: Node2D) -> void:
|
|
276
|
+
if body.is_in_group("player"):
|
|
277
|
+
player_entered.emit()
|
|
278
|
+
|
|
279
|
+
func _on_body_exited(body: Node2D) -> void:
|
|
280
|
+
if body.is_in_group("player"):
|
|
281
|
+
player_exited.emit()
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 4. Input Mapping
|
|
287
|
+
|
|
288
|
+
### Project Settings Input Map
|
|
289
|
+
|
|
290
|
+
Define actions in Project > Project Settings > Input Map:
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
# Common input actions
|
|
294
|
+
move_left: A, Left Arrow, Joystick Left
|
|
295
|
+
move_right: D, Right Arrow, Joystick Right
|
|
296
|
+
move_up: W, Up Arrow, Joystick Up
|
|
297
|
+
move_down: S, Down Arrow, Joystick Down
|
|
298
|
+
jump: Space, Joystick Button 0
|
|
299
|
+
attack: Left Click, Joystick Button 2
|
|
300
|
+
interact: E, Joystick Button 1
|
|
301
|
+
pause: Escape, Joystick Start
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Input Handling Patterns
|
|
305
|
+
|
|
306
|
+
```gdscript
|
|
307
|
+
# Polling (in _process or _physics_process)
|
|
308
|
+
func _physics_process(_delta: float) -> void:
|
|
309
|
+
var move: Vector2 = Input.get_vector("move_left", "move_right", "move_up", "move_down")
|
|
310
|
+
velocity = move * speed
|
|
311
|
+
move_and_slide()
|
|
312
|
+
|
|
313
|
+
# Event-based (in _unhandled_input)
|
|
314
|
+
func _unhandled_input(event: InputEvent) -> void:
|
|
315
|
+
if event.is_action_pressed("interact"):
|
|
316
|
+
interact_with_nearest()
|
|
317
|
+
get_viewport().set_input_as_handled()
|
|
318
|
+
|
|
319
|
+
if event.is_action_pressed("pause"):
|
|
320
|
+
toggle_pause()
|
|
321
|
+
|
|
322
|
+
# Check action strength (analog sticks)
|
|
323
|
+
var aim_x: float = Input.get_action_strength("aim_right") - Input.get_action_strength("aim_left")
|
|
324
|
+
var aim_y: float = Input.get_action_strength("aim_down") - Input.get_action_strength("aim_up")
|
|
325
|
+
var aim: Vector2 = Vector2(aim_x, aim_y)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 5. Resource System
|
|
331
|
+
|
|
332
|
+
### Custom Resources
|
|
333
|
+
|
|
334
|
+
```gdscript
|
|
335
|
+
# weapon_data.gd
|
|
336
|
+
class_name WeaponData
|
|
337
|
+
extends Resource
|
|
338
|
+
|
|
339
|
+
@export var name: String = ""
|
|
340
|
+
@export var damage: int = 10
|
|
341
|
+
@export var attack_speed: float = 1.0
|
|
342
|
+
@export var range: float = 50.0
|
|
343
|
+
@export var icon: Texture2D
|
|
344
|
+
@export var swing_animation: SpriteFrames
|
|
345
|
+
@export_multiline var description: String = ""
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Usage:
|
|
349
|
+
|
|
350
|
+
```gdscript
|
|
351
|
+
# Create .tres files in the editor or load at runtime
|
|
352
|
+
@export var weapon: WeaponData
|
|
353
|
+
|
|
354
|
+
func attack() -> void:
|
|
355
|
+
var damage: int = weapon.damage
|
|
356
|
+
var speed: float = weapon.attack_speed
|
|
357
|
+
apply_damage_in_range(damage, weapon.range)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Preload vs Load
|
|
361
|
+
|
|
362
|
+
```gdscript
|
|
363
|
+
# preload -- resolved at compile time, instant access, increases load time
|
|
364
|
+
const EXPLOSION_SCENE: PackedScene = preload("res://effects/explosion.tscn")
|
|
365
|
+
|
|
366
|
+
# load -- resolved at runtime, may cause hitches if not cached
|
|
367
|
+
func load_level(level_name: String) -> PackedScene:
|
|
368
|
+
return load("res://levels/" + level_name + ".tscn") as PackedScene
|
|
369
|
+
|
|
370
|
+
# ResourceLoader for async loading
|
|
371
|
+
func load_level_async(path: String) -> void:
|
|
372
|
+
ResourceLoader.load_threaded_request(path)
|
|
373
|
+
|
|
374
|
+
func _process(_delta: float) -> void:
|
|
375
|
+
var status: ResourceLoader.ThreadLoadStatus = ResourceLoader.load_threaded_get_status(path)
|
|
376
|
+
if status == ResourceLoader.THREAD_LOAD_LOADED:
|
|
377
|
+
var scene: PackedScene = ResourceLoader.load_threaded_get(path)
|
|
378
|
+
get_tree().change_scene_to_packed(scene)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## 6. Autoload Singletons
|
|
384
|
+
|
|
385
|
+
Register in Project > Project Settings > Autoload.
|
|
386
|
+
|
|
387
|
+
```gdscript
|
|
388
|
+
# game_manager.gd (autoload as GameManager)
|
|
389
|
+
extends Node
|
|
390
|
+
|
|
391
|
+
signal game_state_changed(new_state: String)
|
|
392
|
+
|
|
393
|
+
enum State { MENU, PLAYING, PAUSED, GAME_OVER }
|
|
394
|
+
|
|
395
|
+
var current_state: State = State.MENU
|
|
396
|
+
var score: int = 0
|
|
397
|
+
var high_score: int = 0
|
|
398
|
+
|
|
399
|
+
func change_state(new_state: State) -> void:
|
|
400
|
+
current_state = new_state
|
|
401
|
+
game_state_changed.emit(State.keys()[new_state])
|
|
402
|
+
|
|
403
|
+
func add_score(points: int) -> void:
|
|
404
|
+
score += points
|
|
405
|
+
if score > high_score:
|
|
406
|
+
high_score = score
|
|
407
|
+
|
|
408
|
+
func reset() -> void:
|
|
409
|
+
score = 0
|
|
410
|
+
change_state(State.PLAYING)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
```gdscript
|
|
414
|
+
# audio_manager.gd (autoload as AudioManager)
|
|
415
|
+
extends Node
|
|
416
|
+
|
|
417
|
+
var music_bus: int = AudioServer.get_bus_index("Music")
|
|
418
|
+
var sfx_bus: int = AudioServer.get_bus_index("SFX")
|
|
419
|
+
|
|
420
|
+
@onready var music_player: AudioStreamPlayer = $MusicPlayer
|
|
421
|
+
|
|
422
|
+
func play_music(stream: AudioStream, fade_in: float = 1.0) -> void:
|
|
423
|
+
music_player.stream = stream
|
|
424
|
+
music_player.volume_db = -80.0
|
|
425
|
+
music_player.play()
|
|
426
|
+
var tween: Tween = create_tween()
|
|
427
|
+
tween.tween_property(music_player, "volume_db", 0.0, fade_in)
|
|
428
|
+
|
|
429
|
+
func play_sfx(stream: AudioStream, position: Vector2 = Vector2.ZERO) -> void:
|
|
430
|
+
var player: AudioStreamPlayer2D = AudioStreamPlayer2D.new()
|
|
431
|
+
player.stream = stream
|
|
432
|
+
player.bus = "SFX"
|
|
433
|
+
player.global_position = position
|
|
434
|
+
add_child(player)
|
|
435
|
+
player.play()
|
|
436
|
+
player.finished.connect(player.queue_free)
|
|
437
|
+
|
|
438
|
+
func set_music_volume(linear: float) -> void:
|
|
439
|
+
AudioServer.set_bus_volume_db(music_bus, linear_to_db(linear))
|
|
440
|
+
|
|
441
|
+
func set_sfx_volume(linear: float) -> void:
|
|
442
|
+
AudioServer.set_bus_volume_db(sfx_bus, linear_to_db(linear))
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Access from anywhere:
|
|
446
|
+
|
|
447
|
+
```gdscript
|
|
448
|
+
GameManager.add_score(100)
|
|
449
|
+
AudioManager.play_sfx(hit_sound, global_position)
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## 7. Animation
|
|
455
|
+
|
|
456
|
+
### AnimationPlayer
|
|
457
|
+
|
|
458
|
+
```gdscript
|
|
459
|
+
@onready var anim: AnimationPlayer = $AnimationPlayer
|
|
460
|
+
|
|
461
|
+
func _ready() -> void:
|
|
462
|
+
anim.animation_finished.connect(_on_animation_finished)
|
|
463
|
+
|
|
464
|
+
func play_attack() -> void:
|
|
465
|
+
anim.play("attack")
|
|
466
|
+
|
|
467
|
+
func _on_animation_finished(anim_name: StringName) -> void:
|
|
468
|
+
if anim_name == "attack":
|
|
469
|
+
anim.play("idle")
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### AnimationTree (State Machine)
|
|
473
|
+
|
|
474
|
+
```gdscript
|
|
475
|
+
@onready var anim_tree: AnimationTree = $AnimationTree
|
|
476
|
+
@onready var state_machine: AnimationNodeStateMachinePlayback = anim_tree.get(
|
|
477
|
+
"parameters/playback"
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
func _physics_process(_delta: float) -> void:
|
|
481
|
+
if velocity.length() > 10.0:
|
|
482
|
+
state_machine.travel("run")
|
|
483
|
+
else:
|
|
484
|
+
state_machine.travel("idle")
|
|
485
|
+
|
|
486
|
+
# Blend parameter for blend trees
|
|
487
|
+
anim_tree.set("parameters/blend_position", velocity.normalized())
|
|
488
|
+
|
|
489
|
+
func attack() -> void:
|
|
490
|
+
state_machine.travel("attack")
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Tweens (Procedural Animation)
|
|
494
|
+
|
|
495
|
+
```gdscript
|
|
496
|
+
func flash_white() -> void:
|
|
497
|
+
var tween: Tween = create_tween()
|
|
498
|
+
tween.tween_property(sprite, "modulate", Color.WHITE, 0.05)
|
|
499
|
+
tween.tween_property(sprite, "modulate", Color(1, 1, 1, 1), 0.15)
|
|
500
|
+
|
|
501
|
+
func shake_camera(intensity: float, duration: float) -> void:
|
|
502
|
+
var tween: Tween = create_tween()
|
|
503
|
+
for i in range(10):
|
|
504
|
+
var offset: Vector2 = Vector2(
|
|
505
|
+
randf_range(-intensity, intensity),
|
|
506
|
+
randf_range(-intensity, intensity)
|
|
507
|
+
)
|
|
508
|
+
tween.tween_property(camera, "offset", offset, duration / 10.0)
|
|
509
|
+
tween.tween_property(camera, "offset", Vector2.ZERO, 0.05)
|
|
510
|
+
|
|
511
|
+
func move_to(target: Vector2, duration: float) -> void:
|
|
512
|
+
var tween: Tween = create_tween()
|
|
513
|
+
tween.set_ease(Tween.EASE_OUT)
|
|
514
|
+
tween.set_trans(Tween.TRANS_CUBIC)
|
|
515
|
+
tween.tween_property(self, "global_position", target, duration)
|
|
516
|
+
await tween.finished
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## 8. TileMaps and Terrain
|
|
522
|
+
|
|
523
|
+
### TileMapLayer (Godot 4.3+)
|
|
524
|
+
|
|
525
|
+
```gdscript
|
|
526
|
+
@onready var ground: TileMapLayer = $GroundLayer
|
|
527
|
+
@onready var walls: TileMapLayer = $WallsLayer
|
|
528
|
+
|
|
529
|
+
func place_tile(grid_pos: Vector2i) -> void:
|
|
530
|
+
# set_cell(coords, source_id, atlas_coords, alternative_tile)
|
|
531
|
+
ground.set_cell(grid_pos, 0, Vector2i(0, 0))
|
|
532
|
+
|
|
533
|
+
func remove_tile(grid_pos: Vector2i) -> void:
|
|
534
|
+
ground.erase_cell(grid_pos)
|
|
535
|
+
|
|
536
|
+
func world_to_grid(world_pos: Vector2) -> Vector2i:
|
|
537
|
+
return ground.local_to_map(ground.to_local(world_pos))
|
|
538
|
+
|
|
539
|
+
func grid_to_world(grid_pos: Vector2i) -> Vector2:
|
|
540
|
+
return ground.to_global(ground.map_to_local(grid_pos))
|
|
541
|
+
|
|
542
|
+
func get_tile_at(world_pos: Vector2) -> int:
|
|
543
|
+
var grid_pos: Vector2i = world_to_grid(world_pos)
|
|
544
|
+
return ground.get_cell_source_id(grid_pos)
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## 9. UI System (Control Nodes)
|
|
550
|
+
|
|
551
|
+
### Common UI Structure
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
UIRoot (CanvasLayer)
|
|
555
|
+
+-- HUD (Control - anchored full rect)
|
|
556
|
+
| +-- HealthBar (ProgressBar)
|
|
557
|
+
| +-- ScoreLabel (Label)
|
|
558
|
+
| +-- Minimap (SubViewportContainer)
|
|
559
|
+
+-- PauseMenu (Control - centered, initially hidden)
|
|
560
|
+
| +-- Panel (PanelContainer)
|
|
561
|
+
| +-- VBox (VBoxContainer)
|
|
562
|
+
| +-- ResumeButton (Button)
|
|
563
|
+
| +-- SettingsButton (Button)
|
|
564
|
+
| +-- QuitButton (Button)
|
|
565
|
+
+-- DialogBox (Control)
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### UI Script Pattern
|
|
569
|
+
|
|
570
|
+
```gdscript
|
|
571
|
+
extends Control
|
|
572
|
+
|
|
573
|
+
@onready var health_bar: ProgressBar = $HUD/HealthBar
|
|
574
|
+
@onready var score_label: Label = $HUD/ScoreLabel
|
|
575
|
+
@onready var pause_menu: Control = $PauseMenu
|
|
576
|
+
|
|
577
|
+
func _ready() -> void:
|
|
578
|
+
pause_menu.visible = false
|
|
579
|
+
# Connect to autoload signals
|
|
580
|
+
GameManager.game_state_changed.connect(_on_game_state_changed)
|
|
581
|
+
# Connect buttons
|
|
582
|
+
$PauseMenu/Panel/VBox/ResumeButton.pressed.connect(_on_resume)
|
|
583
|
+
$PauseMenu/Panel/VBox/QuitButton.pressed.connect(_on_quit)
|
|
584
|
+
|
|
585
|
+
func update_health(current: int, maximum: int) -> void:
|
|
586
|
+
health_bar.max_value = maximum
|
|
587
|
+
health_bar.value = current
|
|
588
|
+
|
|
589
|
+
func update_score(score: int) -> void:
|
|
590
|
+
score_label.text = "Score: %d" % score
|
|
591
|
+
|
|
592
|
+
func _on_resume() -> void:
|
|
593
|
+
get_tree().paused = false
|
|
594
|
+
pause_menu.visible = false
|
|
595
|
+
|
|
596
|
+
func _on_quit() -> void:
|
|
597
|
+
get_tree().quit()
|
|
598
|
+
|
|
599
|
+
func _unhandled_input(event: InputEvent) -> void:
|
|
600
|
+
if event.is_action_pressed("pause"):
|
|
601
|
+
get_tree().paused = not get_tree().paused
|
|
602
|
+
pause_menu.visible = get_tree().paused
|
|
603
|
+
get_viewport().set_input_as_handled()
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Theme System
|
|
607
|
+
|
|
608
|
+
```gdscript
|
|
609
|
+
# Apply themes in code
|
|
610
|
+
var theme: Theme = load("res://themes/dark_theme.tres")
|
|
611
|
+
control_node.theme = theme
|
|
612
|
+
|
|
613
|
+
# Override individual properties
|
|
614
|
+
button.add_theme_color_override("font_color", Color.YELLOW)
|
|
615
|
+
button.add_theme_font_size_override("font_size", 24)
|
|
616
|
+
label.add_theme_stylebox_override("normal", custom_stylebox)
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## 10. Multiplayer (High-Level API)
|
|
622
|
+
|
|
623
|
+
### Server/Client Setup
|
|
624
|
+
|
|
625
|
+
```gdscript
|
|
626
|
+
# network_manager.gd (autoload)
|
|
627
|
+
extends Node
|
|
628
|
+
|
|
629
|
+
const PORT: int = 9999
|
|
630
|
+
const MAX_CLIENTS: int = 8
|
|
631
|
+
|
|
632
|
+
signal player_connected(peer_id: int)
|
|
633
|
+
signal player_disconnected(peer_id: int)
|
|
634
|
+
|
|
635
|
+
var players: Dictionary = {}
|
|
636
|
+
|
|
637
|
+
func host_game() -> void:
|
|
638
|
+
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
|
|
639
|
+
peer.create_server(PORT, MAX_CLIENTS)
|
|
640
|
+
multiplayer.multiplayer_peer = peer
|
|
641
|
+
multiplayer.peer_connected.connect(_on_peer_connected)
|
|
642
|
+
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
|
|
643
|
+
|
|
644
|
+
func join_game(address: String) -> void:
|
|
645
|
+
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
|
|
646
|
+
peer.create_client(address, PORT)
|
|
647
|
+
multiplayer.multiplayer_peer = peer
|
|
648
|
+
|
|
649
|
+
func _on_peer_connected(id: int) -> void:
|
|
650
|
+
player_connected.emit(id)
|
|
651
|
+
|
|
652
|
+
func _on_peer_disconnected(id: int) -> void:
|
|
653
|
+
players.erase(id)
|
|
654
|
+
player_disconnected.emit(id)
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### RPCs
|
|
658
|
+
|
|
659
|
+
```gdscript
|
|
660
|
+
# Remote Procedure Calls
|
|
661
|
+
@rpc("any_peer", "reliable")
|
|
662
|
+
func register_player(player_name: String) -> void:
|
|
663
|
+
var sender_id: int = multiplayer.get_remote_sender_id()
|
|
664
|
+
players[sender_id] = {"name": player_name}
|
|
665
|
+
|
|
666
|
+
@rpc("authority", "unreliable")
|
|
667
|
+
func sync_position(pos: Vector2) -> void:
|
|
668
|
+
global_position = pos
|
|
669
|
+
|
|
670
|
+
# Call RPCs
|
|
671
|
+
func _physics_process(_delta: float) -> void:
|
|
672
|
+
if is_multiplayer_authority():
|
|
673
|
+
# Send position to all peers
|
|
674
|
+
sync_position.rpc(global_position)
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
### MultiplayerSpawner and MultiplayerSynchronizer
|
|
678
|
+
|
|
679
|
+
```gdscript
|
|
680
|
+
# Add MultiplayerSpawner as a child of the node that owns spawnable scenes
|
|
681
|
+
# Configure spawn path and auto-spawn list in the Inspector
|
|
682
|
+
|
|
683
|
+
# MultiplayerSynchronizer automatically syncs properties
|
|
684
|
+
# Configure in Inspector: which properties to sync, authority, sync interval
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## 11. Shader Language
|
|
690
|
+
|
|
691
|
+
### Visual Shader vs Written Shader
|
|
692
|
+
|
|
693
|
+
```glsl
|
|
694
|
+
// Simple 2D dissolve shader (res://shaders/dissolve.gdshader)
|
|
695
|
+
shader_type canvas_item;
|
|
696
|
+
|
|
697
|
+
uniform float dissolve_amount : hint_range(0.0, 1.0) = 0.0;
|
|
698
|
+
uniform sampler2D noise_texture;
|
|
699
|
+
uniform vec4 edge_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
|
|
700
|
+
uniform float edge_width : hint_range(0.0, 0.2) = 0.05;
|
|
701
|
+
|
|
702
|
+
void fragment() {
|
|
703
|
+
vec4 tex_color = texture(TEXTURE, UV);
|
|
704
|
+
float noise = texture(noise_texture, UV).r;
|
|
705
|
+
|
|
706
|
+
if (noise < dissolve_amount) {
|
|
707
|
+
discard;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
if (noise < dissolve_amount + edge_width) {
|
|
711
|
+
COLOR = edge_color;
|
|
712
|
+
} else {
|
|
713
|
+
COLOR = tex_color;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Applying Shaders in GDScript
|
|
719
|
+
|
|
720
|
+
```gdscript
|
|
721
|
+
@onready var sprite: Sprite2D = $Sprite2D
|
|
722
|
+
|
|
723
|
+
func dissolve(duration: float) -> void:
|
|
724
|
+
var material: ShaderMaterial = sprite.material as ShaderMaterial
|
|
725
|
+
var tween: Tween = create_tween()
|
|
726
|
+
tween.tween_method(
|
|
727
|
+
func(value: float) -> void: material.set_shader_parameter("dissolve_amount", value),
|
|
728
|
+
0.0, 1.0, duration
|
|
729
|
+
)
|
|
730
|
+
await tween.finished
|
|
731
|
+
queue_free()
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
## 12. Particle Systems
|
|
737
|
+
|
|
738
|
+
### GPUParticles2D
|
|
739
|
+
|
|
740
|
+
```gdscript
|
|
741
|
+
@onready var particles: GPUParticles2D = $GPUParticles2D
|
|
742
|
+
|
|
743
|
+
func emit_burst(count: int) -> void:
|
|
744
|
+
particles.amount = count
|
|
745
|
+
particles.emitting = true
|
|
746
|
+
# One-shot particles auto-stop
|
|
747
|
+
|
|
748
|
+
# Configure ParticleProcessMaterial in Inspector:
|
|
749
|
+
# - Direction, spread, velocity
|
|
750
|
+
# - Gravity
|
|
751
|
+
# - Scale curve
|
|
752
|
+
# - Color gradient
|
|
753
|
+
# - Emission shape (point, sphere, box, ring)
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### CPUParticles2D (Fallback)
|
|
757
|
+
|
|
758
|
+
```gdscript
|
|
759
|
+
# Use CPUParticles2D when GPU particles are not supported
|
|
760
|
+
# or when you need direct control over each particle
|
|
761
|
+
# Same API but runs on CPU -- suitable for small particle counts
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
## 13. GDExtension (Native Performance)
|
|
767
|
+
|
|
768
|
+
### When to Use GDExtension
|
|
769
|
+
|
|
770
|
+
- Performance-critical code (pathfinding, procedural generation)
|
|
771
|
+
- Integrating C/C++ libraries
|
|
772
|
+
- Custom physics or rendering
|
|
773
|
+
|
|
774
|
+
### Setup with godot-cpp
|
|
775
|
+
|
|
776
|
+
```
|
|
777
|
+
project/
|
|
778
|
+
+-- src/
|
|
779
|
+
| +-- my_node.h
|
|
780
|
+
| +-- my_node.cpp
|
|
781
|
+
| +-- register_types.h
|
|
782
|
+
| +-- register_types.cpp
|
|
783
|
+
+-- godot-cpp/ (submodule)
|
|
784
|
+
+-- SConstruct
|
|
785
|
+
+-- my_extension.gdextension
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
```ini
|
|
789
|
+
; my_extension.gdextension
|
|
790
|
+
[configuration]
|
|
791
|
+
entry_symbol = "my_extension_init"
|
|
792
|
+
compatibility_minimum = 4.2
|
|
793
|
+
|
|
794
|
+
[libraries]
|
|
795
|
+
linux.x86_64 = "res://bin/libmyextension.linux.x86_64.so"
|
|
796
|
+
windows.x86_64 = "res://bin/libmyextension.windows.x86_64.dll"
|
|
797
|
+
macos.universal = "res://bin/libmyextension.macos.universal.dylib"
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
## 14. Export and Deployment
|
|
803
|
+
|
|
804
|
+
### Export Presets
|
|
805
|
+
|
|
806
|
+
Configure in Project > Export:
|
|
807
|
+
|
|
808
|
+
```
|
|
809
|
+
# Common export settings
|
|
810
|
+
- Application > Name
|
|
811
|
+
- Application > Icon
|
|
812
|
+
- Binary Format > 64-bit
|
|
813
|
+
- Resources > Include filters: *.tscn, *.tres, *.gd
|
|
814
|
+
- Resources > Exclude filters: *.import, *.md
|
|
815
|
+
|
|
816
|
+
# Platform-specific
|
|
817
|
+
- Windows: embed PCK, sign executable
|
|
818
|
+
- Linux: AppImage or direct binary
|
|
819
|
+
- macOS: App bundle, notarization
|
|
820
|
+
- Android: keystore, permissions, min SDK
|
|
821
|
+
- Web: Thread support, GDExtension not supported
|
|
822
|
+
- iOS: provisioning profile, entitlements
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### Feature Tags
|
|
826
|
+
|
|
827
|
+
```gdscript
|
|
828
|
+
# Check platform at runtime
|
|
829
|
+
if OS.has_feature("web"):
|
|
830
|
+
# Disable unsupported features for web export
|
|
831
|
+
pass
|
|
832
|
+
elif OS.has_feature("mobile"):
|
|
833
|
+
# Touch-friendly UI
|
|
834
|
+
pass
|
|
835
|
+
elif OS.has_feature("pc"):
|
|
836
|
+
# Keyboard/mouse defaults
|
|
837
|
+
pass
|
|
838
|
+
|
|
839
|
+
# Custom feature tags for debug/release
|
|
840
|
+
if OS.has_feature("debug"):
|
|
841
|
+
print("Debug build")
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## 15. Debugging Tools
|
|
847
|
+
|
|
848
|
+
### Built-in Debugger
|
|
849
|
+
|
|
850
|
+
```gdscript
|
|
851
|
+
# Print debugging
|
|
852
|
+
print("Player position: ", global_position)
|
|
853
|
+
print_rich("[color=red]Error:[/color] Invalid state")
|
|
854
|
+
push_warning("Deprecated function called")
|
|
855
|
+
push_error("Critical failure in combat system")
|
|
856
|
+
|
|
857
|
+
# Breakpoints: click the gutter in the script editor
|
|
858
|
+
# Step through code with F10 (step over), F11 (step into)
|
|
859
|
+
|
|
860
|
+
# Assert for development checks (disabled in release)
|
|
861
|
+
assert(health >= 0, "Health cannot be negative")
|
|
862
|
+
assert(weapon != null, "Weapon must be assigned")
|
|
863
|
+
|
|
864
|
+
# Remote scene tree inspector (run game, click "Remote" tab)
|
|
865
|
+
# Profiler (Debugger > Profiler) for frame timing
|
|
866
|
+
# Network profiler for multiplayer debugging
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
### Draw Debug Shapes
|
|
870
|
+
|
|
871
|
+
```gdscript
|
|
872
|
+
func _draw() -> void:
|
|
873
|
+
# Only works on Node2D/Control
|
|
874
|
+
draw_circle(Vector2.ZERO, detection_radius, Color(1, 0, 0, 0.3))
|
|
875
|
+
draw_line(Vector2.ZERO, velocity, Color.GREEN, 2.0)
|
|
876
|
+
draw_rect(Rect2(-16, -16, 32, 32), Color.BLUE, false, 2.0)
|
|
877
|
+
|
|
878
|
+
func update_debug() -> void:
|
|
879
|
+
queue_redraw() # Forces _draw to be called again
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
---
|
|
883
|
+
|
|
884
|
+
## 16. Common Patterns
|
|
885
|
+
|
|
886
|
+
### State Machine
|
|
887
|
+
|
|
888
|
+
```gdscript
|
|
889
|
+
class_name StateMachine
|
|
890
|
+
extends Node
|
|
891
|
+
|
|
892
|
+
@export var initial_state: State
|
|
893
|
+
|
|
894
|
+
var current_state: State
|
|
895
|
+
var states: Dictionary = {}
|
|
896
|
+
|
|
897
|
+
func _ready() -> void:
|
|
898
|
+
for child in get_children():
|
|
899
|
+
if child is State:
|
|
900
|
+
states[child.name.to_lower()] = child
|
|
901
|
+
child.state_machine = self
|
|
902
|
+
if initial_state:
|
|
903
|
+
current_state = initial_state
|
|
904
|
+
current_state.enter()
|
|
905
|
+
|
|
906
|
+
func transition_to(state_name: String) -> void:
|
|
907
|
+
var new_state: State = states.get(state_name.to_lower())
|
|
908
|
+
if new_state == null or new_state == current_state:
|
|
909
|
+
return
|
|
910
|
+
current_state.exit()
|
|
911
|
+
current_state = new_state
|
|
912
|
+
current_state.enter()
|
|
913
|
+
|
|
914
|
+
func _process(delta: float) -> void:
|
|
915
|
+
current_state.update(delta)
|
|
916
|
+
|
|
917
|
+
func _physics_process(delta: float) -> void:
|
|
918
|
+
current_state.physics_update(delta)
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
```gdscript
|
|
922
|
+
# state.gd (base class)
|
|
923
|
+
class_name State
|
|
924
|
+
extends Node
|
|
925
|
+
|
|
926
|
+
var state_machine: StateMachine
|
|
927
|
+
|
|
928
|
+
func enter() -> void:
|
|
929
|
+
pass
|
|
930
|
+
|
|
931
|
+
func exit() -> void:
|
|
932
|
+
pass
|
|
933
|
+
|
|
934
|
+
func update(_delta: float) -> void:
|
|
935
|
+
pass
|
|
936
|
+
|
|
937
|
+
func physics_update(_delta: float) -> void:
|
|
938
|
+
pass
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
### Object Pooling
|
|
942
|
+
|
|
943
|
+
```gdscript
|
|
944
|
+
class_name ObjectPool
|
|
945
|
+
extends Node
|
|
946
|
+
|
|
947
|
+
@export var scene: PackedScene
|
|
948
|
+
@export var pool_size: int = 20
|
|
949
|
+
|
|
950
|
+
var pool: Array[Node] = []
|
|
951
|
+
|
|
952
|
+
func _ready() -> void:
|
|
953
|
+
for i in range(pool_size):
|
|
954
|
+
var instance: Node = scene.instantiate()
|
|
955
|
+
instance.set_process(false)
|
|
956
|
+
instance.visible = false
|
|
957
|
+
add_child(instance)
|
|
958
|
+
pool.append(instance)
|
|
959
|
+
|
|
960
|
+
func get_instance() -> Node:
|
|
961
|
+
for obj in pool:
|
|
962
|
+
if not obj.visible:
|
|
963
|
+
obj.visible = true
|
|
964
|
+
obj.set_process(true)
|
|
965
|
+
return obj
|
|
966
|
+
# Pool exhausted -- expand
|
|
967
|
+
var instance: Node = scene.instantiate()
|
|
968
|
+
add_child(instance)
|
|
969
|
+
pool.append(instance)
|
|
970
|
+
return instance
|
|
971
|
+
|
|
972
|
+
func return_instance(obj: Node) -> void:
|
|
973
|
+
obj.visible = false
|
|
974
|
+
obj.set_process(false)
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
### Save/Load System
|
|
978
|
+
|
|
979
|
+
```gdscript
|
|
980
|
+
const SAVE_PATH: String = "user://savegame.json"
|
|
981
|
+
|
|
982
|
+
func save_game() -> void:
|
|
983
|
+
var save_data: Dictionary = {
|
|
984
|
+
"player": {
|
|
985
|
+
"position": {"x": player.global_position.x, "y": player.global_position.y},
|
|
986
|
+
"health": player.health,
|
|
987
|
+
"score": GameManager.score,
|
|
988
|
+
},
|
|
989
|
+
"level": get_tree().current_scene.scene_file_path,
|
|
990
|
+
"timestamp": Time.get_unix_time_from_system(),
|
|
991
|
+
}
|
|
992
|
+
var file: FileAccess = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
|
993
|
+
file.store_string(JSON.stringify(save_data, "\t"))
|
|
994
|
+
|
|
995
|
+
func load_game() -> void:
|
|
996
|
+
if not FileAccess.file_exists(SAVE_PATH):
|
|
997
|
+
return
|
|
998
|
+
var file: FileAccess = FileAccess.open(SAVE_PATH, FileAccess.READ)
|
|
999
|
+
var data: Dictionary = JSON.parse_string(file.get_as_text())
|
|
1000
|
+
if data == null:
|
|
1001
|
+
push_error("Failed to parse save file")
|
|
1002
|
+
return
|
|
1003
|
+
player.global_position = Vector2(data.player.position.x, data.player.position.y)
|
|
1004
|
+
player.health = data.player.health
|
|
1005
|
+
GameManager.score = data.player.score
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
---
|
|
1009
|
+
|
|
1010
|
+
## 17. Anti-Patterns
|
|
1011
|
+
|
|
1012
|
+
### NEVER
|
|
1013
|
+
|
|
1014
|
+
- Put game logic in `_process` that belongs in `_physics_process` (physics must be deterministic)
|
|
1015
|
+
- Use `get_node()` with hardcoded absolute paths from unrelated scenes (use signals or groups)
|
|
1016
|
+
- Modify children of a node during `_process` iteration (defer with `call_deferred`)
|
|
1017
|
+
- Ignore `delta` in movement calculations (framerate-dependent movement)
|
|
1018
|
+
- Use `load()` in `_process` or `_physics_process` (cache with `preload` or load in `_ready`)
|
|
1019
|
+
- Create circular signal connections (A signals B signals A)
|
|
1020
|
+
- Forget `queue_free()` on dynamically spawned nodes (memory leak)
|
|
1021
|
+
- Use `$NodePath` without `@onready` in variable declarations (node not ready yet)
|
|
1022
|
+
|
|
1023
|
+
### ALWAYS
|
|
1024
|
+
|
|
1025
|
+
- Use `move_and_slide()` for CharacterBody movement (handles collisions correctly)
|
|
1026
|
+
- Use `is_on_floor()` after `move_and_slide()` for ground detection
|
|
1027
|
+
- Free nodes with `queue_free()` instead of `free()` (deferred is safer)
|
|
1028
|
+
- Use groups for cross-cutting concerns (`"enemies"`, `"interactables"`, `"saveable"`)
|
|
1029
|
+
- Use typed variables and return types for better editor support and performance
|
|
1030
|
+
- Organize scenes into logical directories (`scenes/`, `scripts/`, `resources/`, `shaders/`)
|
|
1031
|
+
- Use `@export` for designer-tunable values instead of hardcoding
|
|
1032
|
+
- Test on target platforms early (especially web and mobile)
|