เรดาร์
จาก โรโบวิกิ แหล่งความรู้โรโบโค้ดภาษาไทย
เรดาร์เป็นสิ่งที่จำเป็นมากสำหรับหุ่นยนต์ เพราะถ้าเราไม่มีมัน เราจะไม่สามารถเล็งยิงศัตรูได้ การเคลื่อนที่ก็จะเป็นแบบสุ่มเท่านั้น เหมือนกับการเคลื่อนที่และการยิง การควบคุมเรดาร์มีลำดับวิธีตั้งแต่ง่ายๆ จนไปถึงซับซ้อนมากๆ ในหุ่นยนต์ส่วนมากมักจะเขียนส่วนนี้เพียงเล็กน้อยเท่านั้น ถ้าเทียบกับการยิงและเคลื่อนที่
ในหุ่นยนต์ที่มีการประมวลผลมากๆ จุดที่ดีที่สุดในการวางโค้ดคือคำสั่งแรกๆ ในแต่ละลูป ซึ่งเราจะสามารถป้องกันไม่ให้เรดาร์หลุด ถ้าหุ่นยนต์ถูกข้ามตาเดินเพราะประมวลผลนานเกินเวลาที่กำหนดไว้
เนื้อหา |
ข้อมูลทางเทคนิค
เรดาร์ในโรโบโค้ดจะสามารถหมุนได้เร็วที่สุด 45 องศาต่อ 1 ตา เรดาร์สามารถสแกนหุ่นยนต์ได้ไกล 1200 จุด มุมที่เกิดจากหมุนของเรดาร์ระหว่าง 2 ตาจะสร้างส่วนโค้งของเรดาร์ หุ่นยนต์ทุกตัวที่อยู่ภายใต้ส่วนโค้งของเรดาร์จะถูกส่งไปยังเมธอด onScannedRobot() เรียงลำดับโดยระยะห่าง หุ่นยนต์ตัวที่อยู่ใกล้ที่สุดจะถูกประมวลผลก่อน ในขณะที่ตัวที่อยู่ไกลกว่าจะถูกประมวณผลทีหลัง โดยปกติแล้วเมธอด onScannedRobot() มีความสำคัญในระดับที่ต่ำที่สุด จึงถูกเรียกเป็นสิ่งสุดท้ายในแต่ละตา
เรดาร์แบบตัวต่อตัว
ในการแข่งตัวต่อตัว การล็อคเรดาร์ให้เห็นศัตรูทุกตาสำคัญมาก เพื่อให้การเล็งยิงและการเคลื่อนที่ดียิ่งขึ้น
การล็อดแบบอนันต์
การล็อคแบบอนันต์เป็นวิธีที่ง่ายที่สุด แต่มีข้อเสียคือมีอัตราการหลุดค่อนข้างสูง นั่คือตัวอย่างของโค้ด:
public void run() { // ... turnRadarRight(Double.POSITIVE_INFINITY); } public void onScannedRobot(ScannedRobotEvent e) { // ... setTurnRadarLeft(getRadarTurnRemaining()); }
หลักการทำงานของมันคือให้เรดาร์หมุนไปอนันต์องศา เมื่อเจอศัตรูก็ให้หมุนกลับไปเท่าจำนวนองศาที่เหลืออยู่ ซึ่งมีค่าเป็นอนันต์ จึงเกิดวงวนเช่นนี้ไปเรื่อยๆ
การล็อคแบบแคบ
การล็อคแบบนี้เราจะชี้เรดาห์ไปยังตำแหน่งสุดท้ายที่เรารู้ของศัตรู ทำให้เกิดลำแสงบางๆ ที่ตามศัตรูไปทั้งสนาม มันทำงานได้สมบูรณ์เกือบตลอดเวลาเพราะศัตรูไม่สามารภเลื่อนที่ออกจากสำแสงได้ทันในหนึ่งตา มันอาจมีโอกาสผิดพลาดได้ในบางกรณีที่เกิดไม่บ่อยนัก ทางแก้คือคูณด้วยค่าคงที่ข้างล่าง นี่คือวิธีที่หุ่นส่วนใหญ่ใช้
นี่คือตัวอย่างของการล็อคแบบนี้
import robocode.util.Utils; public void run() { // ... turnRadarRightRadians(Double.POSITIVE_INFINITY); } while (true); } public void onScannedRobot(ScannedRobotEvent e) { double radarTurn = // องศาสัมบูรณ์ถึงศัตรู getHeadingRadians() + e.getBearingRadians() // ลบด้วยมุมของเรดาร์ - getRadarHeadingRadians(); setTurnRadarRightRadians(Utils.normalRelativeAngle(radarTurn)); // ... }
การหลุดในกรณีพิเศษสามารถแก้ได้โดยการคูณด้วยค่าคงที่ดังนี้
- 1.0 เหมือนเดิม
- 1.65 เป็นค่าที่แตบที่สุดที่ทำให้เรดาร์ไม่หลุด
- 2.0 เป็นค่าที่หุ่นส่วนใหญ่ใช้ มันจะทำให้เรดาร์กวาดเกินไปแล้วกลับมา
การล็อคแบบกว้าง
อีกชื่อหนึ่งคือการล็อคแบบสป็อตไลท์ เป็นการกวาดเรดาร์ให้ครอบคลุมหุ่นศัตรูทั้งหุ่น นี่คือตัวอย่างโค้ด
import robocode.util.Utils; public void run() { // ... while(true) { turnRadarRightRadians(Double.POSITIVE_INFINITY); } } public void onScannedRobot(ScannedRobotEvent e) { double absoluteBearing = getHeadingRadians() + e.getBearingRadians(); double radarTurn = Utils.normalRelativeAngle(absoluteBearing - getRadarHeadingRadians()); // ความกว้างแบบมุมของหุ่นศัตรูหาได้ด้วย 2 * atan(18D/ระยะทาง) // คำนวนมุมที่จะหมุนโดยต้องไม่เกินมุมที่หมุนได้ในหนึ่งตา double arcToScan = Math.min(Math.atan(18D / e.getDistance()) * 2, PI/4.0); // เราต้องการหมุนเรดาร์ไปในทางที่หุ่นยนต์ศีตรูเคลื่อนที่อยู่ radarTurn += (radarTurn < 0) ? -arcToScan : arcToScan; setTurnRadarRightRadians(radarTurn); // ... }
เรดาร์แบบตลุมบอน
เรดาร์สำหรับการแข่งตะลุมบอนจะซับซ้อนและใช้พื้นที่มากกว่าเรดาร์แบบหนึ่งต่อหนึ่งเนื่องจากสนามแข่งทั้งสนามจะไม่ตกอยู่ในมุม 45 องศาของการกวาดเรดาร์
เรดาร์แบบหมุน
เรดาร์แบบหมุนเป็นเรดาร์แบบที่ง่ายและซับซ้อนน้อยที่สุด เรดาร์แบบนี้ถูกใช้มากเนื่องจากความง่ายของมัน
public void run() { // ... while(true) { setTurnRadarRightRadians(Double.POSITIVE_INFINITY); } }
เรดาร์แบบสแกนตามอายุ
เป็นเรดาร์ที่จะกวาดหาหุ่นที่ยังไม่ได้เจอนานที่สุด
import java.util.*; import robocode.*; import robocode.util.*; // ... Within robot class static LinkedHashMap<String, Double> enemyHashMap; static double scanDir; static Object sought; public void run() { scanDir = 1; enemyHashMap = new LinkedHashMap<String, Double>(5, 2, true); // ... while(true) { setTurnRadarRightRadians(scanDir * Double.POSITIVE_INFINITY); scan(); } } public void onRobotDeath(RobotDeathEvent e) { enemyHashMap.remove(e.getName()); sought = null; } public void onScannedRobot(ScannedRobotEvent e) { String name = e.getName(); LinkedHashMap<String, Double> ehm = enemyHashMap; ehm.put(name, getHeadingRadians() + e.getBearingRadians()); if ((name == sought || sought == null) && ehm.size() == getOthers()) { scanDir = Utils.normalRelativeAngle(ehm.values().iterator().next() - getRadarHeadingRadians()); sought = ehm.keySet().iterator().next(); } // ... }
เรดาร์ชนิดนี้จะกวาดจนถึงศัตูตัวสุดท้าย แล้วจึงกวาดกลับมาทางเดิม ถ้าการกวาดใช้เวลานานกว่า 4 ตา มันก็จะทำงานเหมือนกับเรดาร์แบบหมุน เรดาร์แบบนี้ถูกใช้ในหุ่นตะลุมบอนขั้นสูงหลายตัว เพราะมันทำให้สามารถกวาดทั้งสนามได้ในระยะเวลาที่สั้นที่สุด
หมายเหตุ
การควบคุมเรดาร์ทั้งหมดในหน้านี้จะสามารถใช้กับชุดคำสั้ง AdvancedRobot และ TeamRobot เท่านั้น ไม่สามารถใช้กับชุดคำสั้ง Robot และ JuniorRobot ได้ โดยในการใช้เรดาร์เกือบทุกแบบ (ยกเว้นการล็อคแบบอนันต์) ค้องการบรรทัดต่อไปนี้ใช้คำสั้ง run()
setAdjustRadarForRobotTurn(true); setAdjustGunForRobotTurn(true); // อันนี้ไม่จำเป็น แต่ควรมีไว้ setAdjustRadarForGunTurn(true);

