เรดาร์

จาก โรโบวิกิ แหล่งความรู้โรโบโค้ดภาษาไทย

ข้ามไปที่: นำทาง, ค้นหา

เรดาร์เป็นสิ่งที่จำเป็นมากสำหรับหุ่นยนต์ เพราะถ้าเราไม่มีมัน เราจะไม่สามารถเล็งยิงศัตรูได้ การเคลื่อนที่ก็จะเป็นแบบสุ่มเท่านั้น เหมือนกับการเคลื่อนที่และการยิง การควบคุมเรดาร์มีลำดับวิธีตั้งแต่ง่ายๆ จนไปถึงซับซ้อนมากๆ ในหุ่นยนต์ส่วนมากมักจะเขียนส่วนนี้เพียงเล็กน้อยเท่านั้น ถ้าเทียบกับการยิงและเคลื่อนที่

ในหุ่นยนต์ที่มีการประมวลผลมากๆ จุดที่ดีที่สุดในการวางโค้ดคือคำสั่งแรกๆ ในแต่ละลูป ซึ่งเราจะสามารถป้องกันไม่ให้เรดาร์หลุด ถ้าหุ่นยนต์ถูกข้ามตาเดินเพราะประมวลผลนานเกินเวลาที่กำหนดไว้

เนื้อหา

ข้อมูลทางเทคนิค

เรดาร์ในโรโบโค้ดจะสามารถหมุนได้เร็วที่สุด 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);
เครื่องมือส่วนตัว
ภาษาอื่น