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置中

遊戲畫面

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