GameShell

終極改造


基本上,司徒要感謝GameShell官方贈送這台開發測試機,讓司徒可以盡情發揮破壞的能力,而司徒打算從外殼改造開始著手,理由很簡單,因為官方設計的外殼根本無法拿來當作掌機遊玩,最基本的DPad都設計的一塌糊塗,更何況四顆ABXY按鈕,L、R按鍵就別想了,因此司徒決定設計一個經典的外殼,而眾所皆知的經典掌機就是丁果A320掌機,所以外形基本上是參考丁果A320外觀,搭配使用的軟體則是:OpenSCAD和KiCAD這兩套開源軟體,而使用的DPad、ABXY以及SS按鈕,則是依據NDSL掌機的尺寸做設計,司徒希望這樣的設計,除了可以延續丁果A320掌機的經典外殼,更可以融合NDSL的好手感,實為一石二鳥之計!

司徒使用OpenSCAD畫了A面外殼


OpenSCAD源碼

$fn = 60;

module meniscus(h=10, r=1){
  difference(){
    translate([r/2+0.1, r/2+0.1, 0]){
      cube([r+0.2, r+0.1, h+0.2], center=true);
    }
    cylinder(h=h+0.2, r=r, center=true);
  }
}

module cube_round_corner(w=10, h=10, z=10, r=1){
  difference(){
    cube([w, h, z], center=true);
    translate([(w/2)-r, (h/2)-r]){
      rotate(0){  
        meniscus(z, r);
      }
    }
    translate([(-w/2)+r, (h/2)-r]){
      rotate(90){
        meniscus(z, r);
      }
    }
    translate([(-w/2)+r, (-h/2)+r]){
      rotate(180){
        meniscus(z, r);
      }
    }
    translate([(w/2)-r, (-h/2)+r]){
      rotate(270){
        meniscus(z, r);
      }
    }
  }
}

module cube_round_all(w=10, h=10, z=10, tk=1, rad=0.3){
 difference(){
    hull(){
      sphere(rad);
      translate([w, 0, 0]){
        sphere(rad);
      }
      translate([w, h, 0]){
        sphere(rad);
      }
      translate([0, h, 0]){
        sphere(rad);
      }
      translate([0, 0, z]){
        sphere(rad);
      }
      translate([w, 0, z]){
        sphere(rad);
      }
      translate([w, h, z]){
        sphere(rad);
      }
      translate([0, h, z]){
        sphere(rad);
      }
    }
    hull(){
      translate([tk, tk, tk]){
        sphere(rad);
      }
      translate([w-tk, tk, tk]){
        sphere(rad);
      }
      translate([w-tk, h-tk, tk]){
        sphere(rad);
      }
      translate([tk, h-tk, tk]){
        sphere(rad);
      }
      translate([tk, tk, z-tk]){
        sphere(rad);
      }
      translate([w-tk, tk, z-tk]){
        sphere(rad);
      }
      translate([w-tk, h-tk, z-tk]){
        sphere(rad);
      }
      translate([tk, h-tk, z-tk]){
        sphere(rad);
      }
    }
  }
}

module screw(h=4, d=1.5, hole=0.6, aid=1){
  difference(){
    union(){
      if(aid > 0){
        translate([0, 0, -h/4]){
          cube([d*3, 1, h/2], center=true);
          cube([1, d*3, h/2], center=true);
        }
      }
      translate([0, 0, -(h/2)]){
        cylinder(h, d, d, center=true);
      }
    }
    cylinder(h*2, hole, hole, center=true);
  }
}

module screw_rev(h=4, d=1.5, hole=0.6, aid=1){
  difference(){
    union(){
      if(aid > 0){
        translate([0, 0, -h/4]){
          cube([d*3, 1, h/2], center=true);
          cube([1, d*3, h/2], center=true);
        }
      }
      translate([0, 0, 0]){
        cylinder(h, d, d, center=true);
      }
    }
    cylinder(h*2, hole, hole, center=true);
  }
}

module c_gamepad_dpad(){
  difference(){
    translate([0, 0, 0]){
      cube([25.7, 26.7, 5]);
    }
    translate([0.6, 0.6, 1.5]){
      cube([24.5, 25.5, 5]);
    }
    translate([25.7/2, 26.7/2, 0]){
      cylinder(5, 12, 12);
    }
  }

  translate([25.7/2, 26.7/2, 0]){
    ndsl_dpad();
  }

  translate([3.25, 3, 1.7]){
    screw_rev(2.9, 2, 0.6, 0);
  }
  translate([3.25, 24, 1.7]){
    screw_rev(2.9, 2, 0.6, 0);
  }
  translate([22.75, 3, 1.7]){
    screw_rev(2.9, 2, 0.6, 0);
  }
  translate([22.75, 24, 1.7]){
    screw_rev(2.9, 2, 0.6, 0);
  }
  translate([0.3, 25/2, 3]){
    rotate([0, 90, 0]){
      cube_round_corner(5, 10, 0.6, 2);
    }
  }
}

module c_gamepad_four(){
  difference(){
    translate([0, 0, 0]){
      cube([28.2, 27.7, 5]);
    }
    translate([0.6, 0.6, 1]){
      cube([27, 26.5, 5]);
    }
    translate([28.7/2, (27.7/2), 0]){
      cylinder(1, 12.7, 12.7);
    }
  }

  translate([28.7/2, 6.35, 0]){
    ndsl_four();
  }

  translate([4.2, 3.5, 1.5]){
    screw_rev(2.75, 2, 0.6, 0);
  }
  translate([4.2, 24.5, 1.5]){
    screw_rev(2.75, 2, 0.6, 0);
  }
  translate([24.5, 3.5, 1.5]){
    screw_rev(2.75, 2, 0.6, 0);
  }
  translate([24.5, 24.5, 1.5]){
    screw_rev(2.75, 2, 0.6, 0);
  }
  translate([0.3, 25/2, 3]){
    rotate([0, 90, 0]){
      cube_round_corner(5, 10, 0.6, 2);
    }
  }
}

module c_gamepad_ss(){
  difference(){
    translate([0, 0, 0]){
      cube([19.2, 16.2, 5]);
    }
    translate([2.1, 4.1, 1]){
      cube([15, 8, 5]);
    }
    translate([0.6, 0.6, 3]){
      cube([18, 15, 5]);
    }
    translate([5.5, 16.2/2, -1]){
      cylinder(5, 1.9, 1.9);
    }
    translate([13.5, 16.2/2, -1]){
      cylinder(5, 1.9, 1.9);
    }
    
    // screw
    translate([3.1, 2, 0.5]){
      cylinder(5, 0.6, 0.6);
    }
    translate([3.1, 14, 0.5]){
      cylinder(5, 0.6, 0.6);
    }
    translate([16.1, 2, 0.5]){
      cylinder(5, 0.6, 0.6);
    }
    translate([16.1, 14, 0.5]){
      cylinder(5, 0.6, 0.6);
    }
  }
}

module ndsl_dpad(){
  union(){
    difference(){
      translate([0, 0, 0]){
        cylinder(1.5, 12, 12);
      }
      translate([0, 0, 1]){
        cylinder(10, 7, 7);
      }
      cube([18.7, 6.7, 5], center=true);
      cube([6.7, 18.7, 5], center=true);
    }
    difference(){
      union(){
        // x
        translate([0, 7, 1.3]){
          difference(){
            cylinder(1.5, 4.8, 4.8);
            cylinder(1.5, 4.2, 4.2);
          }
        }
 
        // y
        translate([-7, 0, 1.3]){
          difference(){
            cylinder(1.5, 4.8, 4.8);
            cylinder(1.5, 4.2, 4.2);
          }
        }
              
        // a
        translate([7, 0, 1.3]){
          difference(){
            cylinder(1.5, 4.8, 4.8);
            cylinder(1.5, 4.2, 4.2);
          }
        }
              
        // b
        translate([0, -7, 1.3]){
          difference(){
            cylinder(1.5, 4.8, 4.8);
            cylinder(1.5, 4.2, 4.2);
          }
        }
      }
      translate([-6, -6, 1]){
        cube([12, 12, 5]);
      }
      translate([0, 0, 0.5]){
        cylinder(10, 7, 7);
      }
    }
  }
}

module ndsl_four(){
  difference(){
    translate([0, 7.5, 0]){
      cylinder(1, 13, 13);
    }
    
    rotate([0, 0, 45]){
      translate([0, 0, -1]){
        cylinder(10, 3.75, 3.75);
      }
      translate([10.5, 0, -1]){
        cylinder(10, 3.75, 3.75);
      }
      translate([0, 10.5, -1]){
        cylinder(10, 3.75, 3.75);
      }
      translate([10.5, 10.5, -1]){
        cylinder(10, 3.75, 3.75);
      }
    }
  }

  union(){
    // a
    translate([0, 15, 1.5]){
      rotate([0, 0, 225]){
        difference(){
          cylinder(2, 5.3, 5.3, center=true);
          cylinder(2, 4.7, 4.7, center=true);
          translate([5, 0, 1]){
            cube([3, 2.2, 5], center=true);
          }
        }
        rotate([0, 0, 270]){
          translate([-4.475, 0, 0]){
            cube([1.25, 1.25, 2], center=true);
          }
        }
      }
    }

    // b
    translate([-7.5, 7.5, 1.5]){
      rotate([0, 0, 315]){
        difference(){
          cylinder(2, 5.3, 5.3, center=true);
          cylinder(2, 4.7, 4.7, center=true);
          translate([5, 0, 1]){
            cube([3, 2.2, 5], center=true);
          }
        }
        rotate([0, 0, 315]){
          translate([-4.3, 0, 0]){
            cube([1.25, 1.25, 2], center=true);
          }
        }
        rotate([0, 0, 135]){
          translate([-4.45, 0, 0]){
            cube([1.25, 1.25, 2], center=true);
          }
        }
      }
    }
    
    // x
    translate([7.5, 7.5, 1.5]){
      rotate([0, 0, 135]){
        difference(){
          cylinder(2, 5.3, 5.3, center=true);
          cylinder(2, 4.7, 4.7, center=true);
          translate([5, 0, 1]){
            cube([3, 2.2, 5], center=true);
          }
        }
        rotate([0, 0, 0]){
          translate([-4.375, 0, 0]){
            cube([1.25, 1.25, 2], center=true);
          }
        }
      }
    }
          
    // y
    translate([0, 0, 1.5]){
      rotate([0, 0, 45]){
        difference(){
          cylinder(2, 5.3, 5.3, center=true);
          cylinder(2, 4.7, 4.7, center=true);
          translate([5, 0, 1]){
            cube([3, 2.2, 5], center=true);
          }
        }
        rotate([0, 0, 40]){
          translate([-4.375, 0, 0]){
            cube([1.25, 1.25, 2], center=true);
          }
        }
        rotate([0, 0, 318]){
          translate([-4.375, 0, 0]){
            cube([1.25, 1.25, 2], center=true);
          }
        }
      }
    }
  }
}

module ndsl_ss(){
  difference(){
    cylinder(1, 3.7, 3.7);
    cylinder(10, 2, 2);
  }
  
  translate([0, 0, 1]){
    difference(){
      cylinder(1, 3.5, 3.5);
      cylinder(1, 3, 3);
    }
  }
}

module lcd(){
  difference(){
    translate([-2, 0, 0]){
      cube([70, 50, 4]);
    }
    translate([6, (50-42)/2 + 0.5, 0]){
      cube([54, 41, 10]);
    }
    translate([3, (50-46)/2, 1]){
      cube([64, 46, 10]);
    }
  }
  
  translate([-2, 49, 4]){
    cube([70, 1, 2]);
  }
  translate([-2, 0, 4]){
    cube([70, 1, 2]);
  }
  translate([-2, 1, 5.35]){
    rotate([0, 90, 0]){
      cylinder(45, 0.6, 0.6);
    }
  }
  translate([63, 1, 5.35]){
    rotate([0, 90, 0]){
      cylinder(5, 0.6, 0.6);
    }
  }
  translate([-2, 49, 5.35]){
    rotate([0, 90, 0]){
      cylinder(70, 0.6, 0.6);
    }
  }
}

// a side
module a_side(){
  difference(){
    union(){
      difference(){
        cube_round_all(122, 50, 15, 1.5, 2);
        translate([-10, -10, 9.5]){
          cube([150, 70, 10]);
        }
        
        // lcd
        translate([(125-70)/2-2.5, 0, -2]){
          cube([70, 50, 5]);
        }
      }
      translate([(125-70)/2-0.5, 0, -2]){
        lcd();
      }
    }
    
    // mini usb
    translate([120, 17, 8]){
      rotate([0, 90, 0]){
        cube_round_corner(6, 8, 10, 2);
      }
    }
    
    // dpad
    translate([0, (50-27)/2-3.5, -2]){
      cube([25.7, 25, 5]);
    }
        
    // four
    translate([94.4, (50-28.5)/2-4.35, -2]){
      cube([27.25, 28, 5]);
    }
    
    // ss
    translate([5.75, 36, -2]){
      cube([19, 14, 5]);
    }
    
    // ss
    translate([97, 36, -2]){
      cube([19, 14, 5]);
    }
  }

  translate([26.25, (50-27)/2-3.5, -2]){
     rotate([0, 0, 90]){
      c_gamepad_dpad();
    }
  }
  translate([94.4, 34.5, -2]){
    rotate([0, 0, 270]){
      c_gamepad_four();
    }
  }
  translate([5.75, 34, -2]){
    c_gamepad_ss();
  }
  translate([97, 34, -2]){
    c_gamepad_ss();
  }

  // screw for core board
  translate([3.75, 3, 3.5]){
    screw_rev(10, 2.5, 0.6, 0);
  }
  translate([3.75, 44.5, 3.5]){
    screw_rev(10, 2.5, 0.6, 0);
  }
  // holder
  translate([22.25, -1, -1.5]){
    difference(){
      cube([3.5, 3, 11]);
      translate([0, 1, 10]){
        cube([3.5, 2, 5]);
      }
    }
  }
  translate([24.35, 47, -2]){
    difference(){
      union(){
        cube([2, 2.5, 11.5]);
        translate([0, -0.5, 3]){
          cube([2, 5, 8.5]);
        }
      }
      translate([0, -1, 10.5]){
        cube([2, 2, 5]);
      }
    }
  }

  // screw for keyboard board
  translate([120-0.5, 4, 1]){
    screw_rev(6, 2.5, 0.6, 0);
  }
  translate([120-0.5, 45.5, 1]){
    screw_rev(6, 2.5, 0.6, 0);
  }
  // holder
  translate([120-25, -1, -1.5]){
    difference(){
      cube([5, 3, 6.5]);
      translate([0, 2, 5.5]){
        cube([5, 2, 5]);
      }
    }
  }
  translate([120-25.5, 48, -2]){
    difference(){
      cube([3.1, 2.5, 7]);
      translate([0, 0, 6]){
        cube([3.1, 1, 5]);
      }
    }
  }
}

// b side
module b_side(){
  difference(){
    cube_round_all(122, 50, 15, 1.5, 2);
    translate([-5, -5, -5]){
      cube([150, 100, 10]);
    }
    
    
    translate([-5, -5, 10]){
      cube([150, 100, 50]);
    }
  }
  
  translate([-2, 10, 12]){
    rotate([0, 90, 0]){
      cube([6, 8, 1.5]);
    }
  }
}

a_side();
//b_side();
//lcd();

裡面構造


接著使用3D印表機列印


裡面構造


LCD部分由於PCB的關係(沒有四面螺絲可以使用),司徒最終使用卡扣的方式固定


這個卡扣設計的還不錯


接著是比較麻煩的部分,因為需要送洗PCB以及焊接PCB,當然使用者也可以使用既有的掌機改造


NDSL的DPad、ABXY和SS按鈕


1mm x 4螺絲


接著鎖上PCB


固定核心板


美美的正面照(由於司徒目前只有1mm x 5的螺絲,所以目前有穿刺的狀況)


吻合的USB孔位


耳機孔位會由中間層來固定


內縮的MicroSD


定位孔花了相當多的時間設計以及測試


LCD置中


遊戲畫面


目前持續設計中間層...


返回上一頁