Files
CosmicClash/CLAUDE.md
T
2026-07-18 14:39:49 +01:00

4.5 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Important rule: never create co-authored commits. Never mention Claude in commits.

Project overview

Cosmic Clash is an open-source, physics-based "vehicle soccer" game (a spiritual successor to Rocket League) built in Godot 4.4, using space ships instead of cars. The project is GDScript/Godot only right now — the "C# backend" mentioned in README.md is planned but not yet started. There is no server-side code; the MVP is local-only play against bots.

Because the gameplay concept (vehicle soccer) can't be copyrighted but specific expression can, all code/art/assets must be original — this is why the project uses Godot instead of Unreal/Unity and ships instead of cars. Keep this in mind when writing code or pulling in assets: don't port or closely mirror Rocket League's actual implementation.

Godot MCP server

This repo vendors godot-mcp as a git submodule at mcp/godot-mcp and registers it in .mcp.json. Prefer the godot-mcp tools over manual file edits or shell commands when the task involves inspecting or modifying the Godot project — reading/editing scenes, nodes, scripts, running the project, or interacting with a live Godot editor/runtime instance. It understands Godot's scene tree and .tscn/.gd structures directly, which is more reliable than hand-parsing them.

Setup after cloning (submodules aren't checked out by default):

git submodule update --init --recursive
cd mcp/godot-mcp
npm install
npm run build

GODOT_PATH (env var in .mcp.json) is left blank to auto-detect the Godot executable; set it explicitly if auto-detection fails on your machine.

Commands

There is no build step, linter, or automated test suite for the GDScript project itself — Godot projects run directly from source.

  • Open the project: open Game/ as a project in the Godot 4.4 editor, or run godot --path Game from the repo root.
  • Run the game: press Play in the editor, or godot --path Game Game/scenes/main_menu.tscn.
  • The mcp/godot-mcp submodule is a separate Node/TypeScript project with its own npm install / npm run build (see above) — it is tooling, not part of the game itself.

Architecture

  • Scene flow: main_menu.tscn → (Play button, main_menu_play_button.gd) → scenes/Game.tscn → on match timer expiry, back to main_menu.tscn. The match is a fixed 150-second timer (game.gd).
  • Game.tscn instances objects/ship.tscn (player-controlled ship), objects/ball.tscn, and objects/goal.tscn over a static terrain body.
  • Ship physics (scripts/ship.gd, class Ship, extends RigidBody3D): all movement is force/torque-based (_integrate_forces), not kinematic — thrust and rotation inputs are converted to world-space forces/torques relative to the ship's orientation, with manual drag and speed/angular-speed clamping applied each physics tick. Physics formulas are commented inline; see FLIGHT_MANUAL.md for the player-facing explanation of controls and flight model.
  • Vehicle.gd (scripts/Vehicle.gd) is a separate, simpler RigidBody3D base class used by objects/vehicle.tscn. It is not currently the base class for Shipship.gd reimplements similar logic directly. Treat these as two independent, currently-diverging implementations rather than a class hierarchy.
  • HUD / telemetry pattern: Ship computes flight data (speed, altitude, attitude, heading, thrust, angular velocity, camera mode) once per physics tick and emits it via signals, only when the value changes past a threshold (see the _last_* fields and *_THRESHOLD constants in ship.gd). HUDController (scripts/HUDController.gd, on scenes/HUD.tscn, instanced inside ship.tscn) discovers the ship and game manager via Godot groups ("ship", "game") rather than direct node paths, connects to their signals, and only updates label text in response — it does no polling. Follow this discovery-by-group + signal-push pattern when adding new instruments or cross-node communication, rather than get_node with hardcoded paths or per-frame polling.
  • Input actions are defined in Game/project.godot under [input] (move_forward, turn_left, turbo, etc.) and read via Input.is_action_pressed(...) — add new controls there rather than hardcoding key/button checks.
  • Physics engine is Jolt (Game/project.godot, [physics] 3d/physics_engine="Jolt Physics").