From 9a4d96ae54b4cfd6a9e2d407c8be5cb2b03cf4c2 Mon Sep 17 00:00:00 2001 From: type-two Date: Mon, 27 Jul 2026 21:48:37 +1000 Subject: [PATCH] MINI MERK, MAXI MERK (6 wheels), HARDON SHAGGEN panel van New moke body style: open slab tub, no doors, exposed seats, windscreen, rip-off det_roof canopy on posts, optional extra visual axles (physics stays 4-ray). New van style: cargo box from cab to tail with det_tailgate. Smoke test ram made deterministic (re-aim loop instead of blind throttle). Co-Authored-By: Claude Fable 5 --- cars/hardon_shaggen/car.glb | Bin 0 -> 32140 bytes cars/hardon_shaggen/car.glb.import | 42 +++++++++++++ cars/hardon_shaggen/stats.tres | 13 ++++ cars/maxi_merk/car.glb | Bin 0 -> 46640 bytes cars/maxi_merk/car.glb.import | 42 +++++++++++++ cars/maxi_merk/stats.tres | 13 ++++ cars/mini_merk/car.glb | Bin 0 -> 37112 bytes cars/mini_merk/car.glb.import | 42 +++++++++++++ cars/mini_merk/stats.tres | 13 ++++ shot_datto_120y.png.import | 40 ++++++++++++ shot_floored_xd.png.import | 40 ++++++++++++ shot_turdrunner_slur.png.import | 40 ++++++++++++ tests/smoke.gd | 14 +++-- tools/build_cars.py | 96 ++++++++++++++++++++++++++++- 14 files changed, 389 insertions(+), 6 deletions(-) create mode 100644 cars/hardon_shaggen/car.glb create mode 100644 cars/hardon_shaggen/car.glb.import create mode 100644 cars/hardon_shaggen/stats.tres create mode 100644 cars/maxi_merk/car.glb create mode 100644 cars/maxi_merk/car.glb.import create mode 100644 cars/maxi_merk/stats.tres create mode 100644 cars/mini_merk/car.glb create mode 100644 cars/mini_merk/car.glb.import create mode 100644 cars/mini_merk/stats.tres create mode 100644 shot_datto_120y.png.import create mode 100644 shot_floored_xd.png.import create mode 100644 shot_turdrunner_slur.png.import diff --git a/cars/hardon_shaggen/car.glb b/cars/hardon_shaggen/car.glb new file mode 100644 index 0000000000000000000000000000000000000000..2533aee748f70875726eca9e88d413824f054e1a GIT binary patch literal 32140 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 literal 0 HcmV?d00001 diff --git a/cars/hardon_shaggen/car.glb.import b/cars/hardon_shaggen/car.glb.import new file mode 100644 index 0000000..77fc17a --- /dev/null +++ b/cars/hardon_shaggen/car.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bts43pvbjjekx" +path="res://.godot/imported/car.glb-9f1ddebc9927c2e6e83490ea92684b71.scn" + +[deps] + +source_file="res://cars/hardon_shaggen/car.glb" +dest_files=["res://.godot/imported/car.glb-9f1ddebc9927c2e6e83490ea92684b71.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/cars/hardon_shaggen/stats.tres b/cars/hardon_shaggen/stats.tres new file mode 100644 index 0000000..4d847c5 --- /dev/null +++ b/cars/hardon_shaggen/stats.tres @@ -0,0 +1,13 @@ +[gd_resource type="Resource" script_class="CarStats" load_steps=2 format=3] + +[ext_resource type="Script" path="res://src/car_stats.gd" id="1"] + +[resource] +script = ExtResource("1") +display_name = "HARDON SHAGGEN" +model_path = "res://cars/hardon_shaggen/car.glb" +engine_power = 14.0 +mass = 1250.0 +grip = 5.5 +length = 4.55 +width = 1.72 diff --git a/cars/maxi_merk/car.glb b/cars/maxi_merk/car.glb new file mode 100644 index 0000000000000000000000000000000000000000..4d25bd50c042eea5d7fa0a439128986fde11d8bf GIT binary patch literal 46640 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 PJ)S$*h0k4hUf_QKr8q}w literal 0 HcmV?d00001 diff --git a/cars/mini_merk/car.glb.import b/cars/mini_merk/car.glb.import new file mode 100644 index 0000000..f9b1208 --- /dev/null +++ b/cars/mini_merk/car.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://b8cnylnv16dt" +path="res://.godot/imported/car.glb-6a6391a8dfa537986da8e39a8baed19e.scn" + +[deps] + +source_file="res://cars/mini_merk/car.glb" +dest_files=["res://.godot/imported/car.glb-6a6391a8dfa537986da8e39a8baed19e.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/cars/mini_merk/stats.tres b/cars/mini_merk/stats.tres new file mode 100644 index 0000000..1889d14 --- /dev/null +++ b/cars/mini_merk/stats.tres @@ -0,0 +1,13 @@ +[gd_resource type="Resource" script_class="CarStats" load_steps=2 format=3] + +[ext_resource type="Script" path="res://src/car_stats.gd" id="1"] + +[resource] +script = ExtResource("1") +display_name = "MINI MERK" +model_path = "res://cars/mini_merk/car.glb" +engine_power = 9.0 +mass = 600.0 +grip = 7.5 +length = 3.05 +width = 1.42 diff --git a/shot_datto_120y.png.import b/shot_datto_120y.png.import new file mode 100644 index 0000000..7915fa6 --- /dev/null +++ b/shot_datto_120y.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csax7yqjgptvt" +path="res://.godot/imported/shot_datto_120y.png-85e191822a21ddbb3112ee0a47028b7f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://shot_datto_120y.png" +dest_files=["res://.godot/imported/shot_datto_120y.png-85e191822a21ddbb3112ee0a47028b7f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/shot_floored_xd.png.import b/shot_floored_xd.png.import new file mode 100644 index 0000000..8aa7c08 --- /dev/null +++ b/shot_floored_xd.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cd5quvmmdk7wy" +path="res://.godot/imported/shot_floored_xd.png-6498dca165edfeb647825ab5252ac5e1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://shot_floored_xd.png" +dest_files=["res://.godot/imported/shot_floored_xd.png-6498dca165edfeb647825ab5252ac5e1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/shot_turdrunner_slur.png.import b/shot_turdrunner_slur.png.import new file mode 100644 index 0000000..4630737 --- /dev/null +++ b/shot_turdrunner_slur.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxit0l621tsok" +path="res://.godot/imported/shot_turdrunner_slur.png-2dfbb7c644ee0226f53c86ea197285f9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://shot_turdrunner_slur.png" +dest_files=["res://.godot/imported/shot_turdrunner_slur.png-2dfbb7c644ee0226f53c86ea197285f9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/tests/smoke.gd b/tests/smoke.gd index 2a6c333..ec3e2cf 100644 --- a/tests/smoke.gd +++ b/tests/smoke.gd @@ -38,13 +38,19 @@ func _run() -> void: assert(game.traffic.size() == Game.TRAFFIC_COUNT["crash"], "traffic missing") var victim: TrafficCar = game.traffic[0] await physics_frame # traffic takes position on its first physics tick - game.car.global_position = victim.global_position - victim.global_basis.z * 15.0 - game.car.look_at(victim.global_position) Input.action_press("throttle") - for i in 240: - await physics_frame + for attempt in 8: # re-aim: victim keeps moving along the loop if not victim.live: break + var to_victim := (victim.global_position - game.car.global_position) + game.car.global_position = victim.global_position - victim.global_basis.z * 8.0 + game.car.look_at(victim.global_position) + to_victim = (victim.global_position - game.car.global_position).normalized() + game.car.linear_velocity = to_victim * 18.0 + for i in 30: + await physics_frame + if not victim.live: + break Input.action_release("throttle") assert(not victim.live, "rammed traffic never went dynamic") assert(game.score > 0.0, "crash mode scored nothing") diff --git a/tools/build_cars.py b/tools/build_cars.py index 36c42bf..0227b9f 100644 --- a/tools/build_cars.py +++ b/tools/build_cars.py @@ -67,6 +67,18 @@ CARS = { bonnet=0.95, boot=0.30, roof=1.36, roof_rear=0.95, ohang_f=0.78, ohang_r=0.70, wheel=0.27, paint=(0.10, 0.55, 0.52, 1), chrome_bumpers=False, hatch=True), + "hardon_shaggen": dict(L=4.55, W=1.72, nose=0.66, belt=0.86, tail=0.84, + bonnet=1.35, boot=2.05, roof=1.42, roof_rear=0.25, + ohang_f=0.85, ohang_r=0.95, wheel=0.29, + paint=(0.70, 0.72, 0.58, 1), chrome_bumpers=True, hatch=False, + doors=2, van=True), + # mokes use the open-tub builder: style="moke" + "mini_merk": dict(style="moke", L=3.05, W=1.42, nose=0.60, tub=0.66, canopy=1.38, + bonnet=0.85, ohang_f=0.55, ohang_r=0.55, wheel=0.26, + paint=(0.95, 0.62, 0.72, 1)), + "maxi_merk": dict(style="moke", L=4.35, W=1.45, nose=0.60, tub=0.66, canopy=1.38, + bonnet=1.00, ohang_f=0.60, ohang_r=0.60, wheel=0.26, + paint=(0.93, 0.78, 0.05, 1), extra_axles=[1.35], rear_bench=True), } @@ -191,13 +203,19 @@ def build(car_id, s): parts.append(box("det_bumper_f", (0, f + 0.05, bottom + 0.16), (W + 0.06, 0.15, 0.16), bumper_mat)) parts.append(box("det_bumper_r", (0, r - 0.05, bottom + 0.16), (W + 0.06, 0.15, 0.16), bumper_mat)) + if s.get("van"): # cargo box from cab rear to tail, plus rip-off tailgate + parts.append(box("van_box", (0, (boot_y + r) / 2, (s["belt"] + s["roof"]) / 2), + (W * 0.94, boot_y - r - 0.05, s["roof"] - s["belt"]), paint)) + parts.append(box("det_tailgate", (0, r - 0.03, (s["belt"] + s["roof"]) / 2 - 0.04), + (W * 0.72, 0.05, s["roof"] - s["belt"] - 0.22), paint_dk)) + # bonnet plate follows the bonnet slope; optional two-tone accent colour bonnet_mat = material("bonnet", s["bonnet_color"], rough=0.35) if "bonnet_color" in s else paint_dk by1, bz1, by2, bz2 = f - 0.35, nose2, ws_base + 0.03, s["belt"] ang = math.atan2(bz2 - bz1, by2 - by1) parts.append(box("det_bonnet", ((0, (by1 + by2) / 2, (bz1 + bz2) / 2 + 0.02)), (W * 0.7, math.hypot(by2 - by1, bz2 - bz1) - 0.1, 0.04), bonnet_mat, rot_x=-ang)) - if not s["hatch"]: + if not s["hatch"] and not s.get("van"): ty1, tz1, ty2, tz2 = boot_y - 0.03, s["belt"], r + 0.1, s["tail"] ang = math.atan2(tz2 - tz1, ty2 - ty1) parts.append(box("det_boot", ((0, (ty1 + ty2) / 2, (tz1 + tz2) / 2 + 0.02)), @@ -236,6 +254,80 @@ def build(car_id, s): print("built", car_id, "->", path) +def build_moke(car_id, s): + """Open-top Moke: slab tub, no doors, exposed seats, rip-off canopy.""" + wipe() + paint = material("paint", s["paint"], rough=0.45) + glass = material("glass", GLASS, rough=0.2) + tyre = material("tyre", TYRE, rough=0.9) + chrome = material("chrome", CHROME, metallic=1.0, rough=0.25) + dark = material("dark", DARK, rough=0.8) + canvas = material("canvas", (0.07, 0.07, 0.07, 1), rough=0.95) + + L, W = s["L"], s["W"] + f, r, hw = L / 2, -L / 2, W / 2 + bottom = 0.25 + tub = s["tub"] + ws_base = f - s["bonnet"] + + body = extrude_profile("body", [ + (f, bottom + 0.1), (f, s["nose"]), (f - 0.15, tub), (r + 0.05, tub), + (r, s["nose"]), (r, bottom + 0.1), (r + 0.15, bottom), (f - 0.15, bottom), + ], hw, paint) + + parts = [box("windscreen", (0, ws_base, tub + 0.26), (W * 0.88, 0.04, 0.5), glass, rot_x=0.12)] + canopy_len = ws_base - r - 0.05 + parts.append(box("det_roof", (0, (ws_base + r) / 2, s["canopy"]), (W * 0.98, canopy_len, 0.06), canvas)) + for py in (ws_base, r + 0.15): + for sx in (-1, 1): + parts.append(box("post", (sx * (hw - 0.08), py, (tub + s["canopy"]) / 2), + (0.05, 0.05, s["canopy"] - tub), dark)) + seats = [(ws_base - 0.55, -0.33), (ws_base - 0.55, 0.33)] + if s.get("rear_bench"): + seats += [(ws_base - 1.45, -0.33), (ws_base - 1.45, 0.33)] + for i, (sy, sx) in enumerate(seats): + parts.append(box("trim_seat%d" % i, (sx, sy, tub + 0.10), (0.45, 0.45, 0.22), dark)) + parts.append(box("trim_seatback%d" % i, (sx, sy - 0.22, tub + 0.32), (0.45, 0.08, 0.42), dark)) + for side, sx in (("l", -1), ("r", 1)): + parts.append(box("det_mirror_%s" % side, (sx * (hw + 0.07), ws_base + 0.02, tub + 0.42), + (0.12, 0.08, 0.12), dark)) + parts.append(box("det_bumper_f", (0, f + 0.05, bottom + 0.14), (W + 0.04, 0.13, 0.13), chrome)) + parts.append(box("det_bumper_r", (0, r - 0.05, bottom + 0.14), (W + 0.04, 0.13, 0.13), chrome)) + parts.append(box("det_bonnet", (0, (f - 0.12 + ws_base) / 2, tub + 0.015), + (W * 0.6, f - 0.12 - ws_base - 0.05, 0.04), paint)) + + trim = [ + box("trim_grille", (0, f + 0.01, s["nose"] - 0.13), (W * 0.45, 0.05, 0.11), dark), + box("trim_light_fl", (-W * 0.33, f + 0.02, s["nose"] - 0.12), (0.18, 0.05, 0.14), material("lf", LIGHT_F)), + box("trim_light_fr", (W * 0.33, f + 0.02, s["nose"] - 0.12), (0.18, 0.05, 0.14), material("lf2", LIGHT_F)), + box("trim_light_rl", (-W * 0.32, r - 0.02, s["nose"] - 0.12), (0.2, 0.05, 0.11), material("lr", LIGHT_R)), + box("trim_light_rr", (W * 0.32, r - 0.02, s["nose"] - 0.12), (0.2, 0.05, 0.11), material("lr2", LIGHT_R)), + ] + + ax_f, ax_r = f - s["ohang_f"], r + s["ohang_r"] + wx = hw - 0.09 + axles = [ax_f, ax_r] + [r + e for e in s.get("extra_axles", [])] + wheels = [] + for i, ay in enumerate(axles): + wheels.append(wheel("wheel_%dl" % i, -wx, ay, s["wheel"], tyre)) + wheels.append(wheel("wheel_%dr" % i, wx, ay, s["wheel"], tyre)) + + for obj in parts + trim + wheels: + obj.parent = body + body.location.z = -0.75 + + out_dir = os.path.join(OUT, car_id) + os.makedirs(out_dir, exist_ok=True) + path = os.path.join(out_dir, "car.glb") + for obj in bpy.data.objects: + obj.select_set(True) + bpy.ops.export_scene.gltf(filepath=path, export_format="GLB", use_selection=True) + print("built", car_id, "->", path) + + for car_id, spec in CARS.items(): - build(car_id, spec) + if spec.get("style") == "moke": + build_moke(car_id, spec) + else: + build(car_id, spec) print("done: %d cars" % len(CARS))