Java编程进阶:智能仿真无人机项目4.0
一、项目前期准备
V4 版本在 V3 “双向对抗” 基础上,新增定点任务处理、鼠标交互、多线程协作、状态机管理四大核心功能,新手需在 V3 基础(集合、线程通信、扫描攻击)上,额外掌握以下知识点:
1. 鼠标事件监听(MouseListener)
- 作用:捕捉鼠标操作(点击、按压、释放等),实现 “鼠标点击生成任务” 的交互;
- 核心接口:
MouseListener,需重写 5 个方法(重点用mousePressed:鼠标按压时触发); - 关键步骤:给窗口注册鼠标监听器→重写
mousePressed方法→获取鼠标点击坐标。
2. 距离计算(勾股定理)
- 作用:找到 “离任务点最近的无人机”,实现任务分配逻辑;
代码实现:
(int) Math.sqrt((t.x - d.x)*(t.x - d.x) + (t.y - d.y)*(t.y - d.y));公式:两点(无人机坐标(x1,y1)、任务坐标(x2,y2))距离 dis =
3.多线程协作
- 新增
TaskProThread(任务处理线程),与原有DroneThread(无人机线程)协同工作; - 核心:通过共享
droneList和taskList,实现 “任务生成→分配→执行→完成” 的闭环。
4. 状态机管理
- 无人机新增 3 种状态:
0(巡逻)、1(跟随入侵者)、2(处理任务); - 核心:状态决定行为(如巡逻时随机运动,处理任务时飞向任务点),状态切换通过修改
state属性实现。
5. 坐标与速度适配
- 任务点导向速度:通过计算无人机与任务点的坐标差,调整
runSpeedx和runSpeedy,让无人机飞向任务点。
二、项目结构解析
V4 版本的核心变化是新增 “任务体系”,实现 “鼠标点击生成任务→系统分配给最近无人机→无人机完成任务后回归巡逻” 的完整流程,同时保留 V3 的双向对抗功能,形成 “任务处理 + 敌对对抗” 的复合场景。
1.项目结构分析
| 类名 | 作用 | 核心新增技术点 |
|---|---|---|
Task | 任务实体类(存储任务坐标、状态、生命值) | 任务可视化绘制、状态管理(未分配 / 已分配 / 完成) |
TaskProThread | 任务处理线程(分配任务、监控任务进度) | 距离计算、最近无人机匹配、速度调整 |
Drone | 无人机实体类(新增状态、任务相关属性) | 多状态管理、状态可视化(颜色区分)、速度适配 |
DroneListener | 监听器(新增鼠标监听,生成任务) | MouseListener、鼠标坐标获取 |
DroneThread | 核心线程(保留对抗 + 新增任务绘制) | 状态判断、任务与对抗逻辑兼容 |
DroneUI | 界面搭建(新增任务集合、鼠标监听器注册) | 多集合共享、鼠标监听器绑定 |
Intruder | 入侵者实体类(优化边界、新增生命值显示) | 边界调整、生命值可视化 |
2.项目核心逻辑流程:
- 任务生成:用户鼠标点击窗口→监听器捕捉坐标→创建Task对象→存入taskList;
- 任务分配:TaskProThread遍历taskList→找到未分配任务→计算所有无人机到任务点的距离→分配给最近的空闲无人机(state=0)→无人机状态改为2(处理任务);
- 任务执行:无人机线程根据state=2→调整速度飞向任务点→到达后扣除任务生命值;
- 任务完成:任务生命值≤0→状态改为2(已完成)→无人机状态重置为0(巡逻);
- 并行对抗:任务执行过程中,无人机与入侵者的双向扫描攻击正常进行。
三、核心模块详细讲解
1:新增实体类 ——Task(任务类)
Task类是 “定点任务” 的载体,封装了任务的核心信息,支持可视化绘制和状态管理。
(1)关键代码解析
import java.awt.Graphics; import java.awt.Color; public class Task { int x; // 任务点x坐标(鼠标点击位置) int y; // 任务点y坐标 int state; // 任务状态:0=未分配,1=已分配,2=已完成 int blood; // 任务生命值(需无人机攻击多次完成) // 构造方法:创建任务时初始化坐标和状态 public Task(int x, int y, int state) { this.x = x; this.y = y; this.state = state; this.blood = 10; // 初始生命值10(需攻击10次完成) } // 绘制任务点(可视化,新手能直观看到任务位置) public void draw(Graphics g) { if (blood <= 0) { state = 2; // 生命值为0,标记为已完成 return; } g.setColor(Color.BLACK); // 绘制任务点:黑色矩形(左上角(x,y),宽80,高80) g.fillRect(x, y, 80, 80); } // Getter/Setter方法:获取/修改坐标、状态(供其他类访问) public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getState() { return state; } public void setState(int state) { this.state = state; } }(2)理解要点
- 任务状态设计:
0-1-2的状态流转,确保任务不会重复分配,符合 “生成→分配→完成” 的逻辑; - 任务生命值:blood = 10 意味着无人机需要到达任务点附近 10 次(每次扣 1 血)才能完成任务,模拟 “持续处理任务” 的场景;
- 可视化绘制:fillRect 绘制黑色矩形,新手能直接在窗口看到鼠标点击生成的任务点。
2.新增线程 ——TaskProThread(任务处理线程)
这是 V4 版本的核心新增线程,负责 “任务分配” 和 “任务进度监控”,是连接 “任务生成” 和 “无人机执行” 的桥梁。
(1)关键代码解析
import java.util.ArrayList; public class TaskProThread extends Thread { ArrayList<Drone> droneList; // 共享无人机集合 ArrayList<Task> taskList; // 共享任务集合 public void run() { while (true) { // 死循环:持续监控任务 try { Thread.sleep(30); // 每30毫秒检查一次,避免频繁计算 } catch (InterruptedException e) { throw new RuntimeException(e); } // 遍历所有任务,寻找未分配的任务(state=0) for (int i = 0; i < taskList.size(); i++) { Task t = taskList.get(i); if (t.state == 0) { // 找到未分配的任务 int minDis = 1000; // 初始化最小距离(足够大即可) int targetDroneIndex = 0; // 最近无人机的索引 // 遍历所有无人机,找到距离任务点最近的空闲无人机(state=0:巡逻中) for (int j = 0; j < droneList.size(); j++) { Drone d = droneList.get(j); // 跳过正在跟随入侵者(state=1)或处理其他任务(state=2)的无人机 if (d.state == 1 || d.state == 2) { continue; } // 勾股定理计算无人机到任务点的距离 int dis = (int) Math.sqrt( (t.x - d.x) * (t.x - d.x) + (t.y - d.y) * (t.y - d.y) ); // 更新最小距离和对应的无人机索引 if (dis < minDis) { minDis = dis; targetDroneIndex = j; } } // 给最近的无人机分配任务 Drone targetDrone = droneList.get(targetDroneIndex); // 计算无人机到任务点的坐标差(用于调整速度方向) int dx = t.x - targetDrone.x; // x方向差值(任务点 - 无人机x) int dy = t.y - targetDrone.y; // y方向差值(任务点 - 无人机y) // 记录任务索引(无人机执行时需对应任务) targetDrone.tindex = i; // 基础速度(取无人机原有速度的绝对值,保证速度大小不变) int baseSpeedX = Math.abs(targetDrone.speedx); int baseSpeedY = Math.abs(targetDrone.speedy); // 调整x方向速度:无人机在任务点左边(dx>0)则向右飞(+baseSpeedX),否则向左(-baseSpeedX) targetDrone.runSpeedx = dx > 0 ? baseSpeedX : -baseSpeedX; // 调整y方向速度:同理,确保飞向任务点 targetDrone.runSpeedy = dy > 0 ? baseSpeedY : -baseSpeedY; // 更新状态:任务改为“已分配”(state=1),无人机改为“处理任务”(state=2) t.state = 1; targetDrone.state = 2; } } // 监控任务执行进度:无人机到达任务点后,扣除任务生命值 if (taskList.size() > 0) { for (int i = 0; i < droneList.size(); i++) { Drone d = droneList.get(i); if (d.state == 2) { // 只处理正在执行任务的无人机 Task t = taskList.get(d.tindex); // 获取对应的任务 // 判断无人机是否到达任务点(无人机中心+120像素,覆盖任务矩形范围) if (d.x + 120 >= t.x && d.x + 120 <= t.x + 80 && d.y + 120 >= t.y && d.y + 120 <= t.y + 80) { d.runSpeedx = 0; // 到达后停止移动 d.runSpeedy = 0; t.blood--; // 扣除任务生命值(完成一次处理) } // 任务完成(生命值≤0):重置无人机和任务状态 if (t.blood <= 0) { d.state = 0; // 无人机回归巡逻状态 d.tindex = 0; // 清空任务索引 t.state = 2; // 任务标记为已完成 } } } } } } }(2)理解要点
任务分配流程
- 遍历任务集合,筛选出 “未分配”(state=0)的任务;
- 遍历无人机集合,跳过忙碌的无人机(state=1/2),计算空闲无人机到任务点的距离;
- 选中距离最近的无人机,根据坐标差调整速度方向(确保飞向任务点);
- 更新任务和无人机的状态,完成分配。
距离计算的意义
- 用勾股定理计算 “直线距离”,确保分配的是 “最近” 的无人机,符合 “高效任务处理” 的逻辑;
- 新手无需深入理解数学原理,直接复用
Math.sqrt的代码即可,重点关注 “距离对比” 的逻辑。
速度调整逻辑
- 核心:通过
dx(x 方向差值)判断无人机在任务点的左 / 右,通过dy判断上 / 下; - 示例:若
dx>0(任务点在无人机右边),则runSpeedx=baseSpeedX(向右飞),反之向左飞,确保无人机精准飞向任务点。
3.实体类优化 ——Drone(多状态管理)
V4 版本的Drone类新增了状态、任务索引、运行速度等属性,支持 “巡逻→跟随→任务” 的状态切换,且状态通过颜色可视化。
(1)关键代码解析
import java.awt.Graphics; import java.awt.Color; public class Drone { // 原有属性(坐标、速度、尺寸等) int x, y, speedx, speedy, size; // 新增属性:任务相关 int tindex; // 绑定的任务索引(对应taskList中的位置) int state; // 状态:0=巡逻,1=跟随入侵者,2=处理任务 // 新增属性:速度控制(runSpeedx/y是实际运行速度,可动态调整) int runSpeedx, runSpeedy; // 原有属性(雷达范围、状态灯尺寸) int stateSize; int scanSize; // 构造方法:初始化属性,默认状态为0(巡逻) public Drone(int x, int y, int state, int speedx, int speedy) { this.x = x; this.y = y; this.state = state; // 初始状态:巡逻(0) this.size = 30; this.stateSize = 15; this.scanSize = 100; this.speedx = speedx; this.speedy = speedy; this.runSpeedx = speedx; // 初始运行速度=默认速度 this.runSpeedy = speedy; } // 绘制无人机(新增状态颜色区分,可视化关键) public void drawDrone(Graphics bg) { // 1. 绘制雷达范围(蓝色半透明椭圆,与V3一致) Color color1 = new Color(0, 0, 255, 60); bg.setColor(color1); bg.fillOval(x, y, scanSize, scanSize); // 2. 绘制无人机主体(绿色椭圆,与V3一致) Color color2 = new Color(64, 195, 66); bg.setColor(color2); bg.fillOval(x + 35, y + 35, size, size); // 3. 绘制状态灯(根据状态改变颜色,新手直观区分) Color color3; if (state == 0) { // 巡逻状态:红色 color3 = new Color(255, 0, 0); } else { // 跟随(1)或处理任务(2):黄色 color3 = new Color(255, 255, 0); } bg.setColor(color3); bg.fillOval(x + 42, y + 42, stateSize, stateSize); } // 移动方法(根据状态调整速度,核心逻辑) public void move() { // 巡逻状态(state=0):使用默认速度,随机运动 if (state == 0) { runSpeedx = speedx; runSpeedy = speedy; } // 边界检测(与V3类似,优化反弹逻辑) // 水平边界:左200,右800(防守区范围) if (x > 300 + 600 || x < 200) { if (x < 200) { runSpeedx = -runSpeedx; // 反弹 speedx = -speedx; x += size; // 避免卡在边界 } else { runSpeedx = -runSpeedx; speedx = -speedx; x -= size; } } // 垂直边界:上175,下675(防守区范围) if (y > 175 + 500 || y < 175) { if (y < 175) { runSpeedy = -runSpeedy; speedy = -speedy; y += size; } else { runSpeedy = -runSpeedy; speedy = -speedy; y -= size; } } // 更新坐标(使用runSpeedx/y,支持动态速度调整) x += runSpeedx; y += runSpeedy; } }(2)理解要点
状态管理与可视化:
- 状态切换:通过修改
state属性实现(如任务分配时设为 2,任务完成后设为 0); - 颜色区分:巡逻(红色灯)、跟随 / 任务(黄色灯),新手无需看代码,直接观察窗口即可判断无人机状态;
- 速度分离:
speedx/y是默认速度(巡逻时用),runSpeedx/y是实际运行速度(跟随 / 任务时动态调整),避免速度冲突。
4..交互核心升级 ——DroneListener(新增鼠标监听)
监听器同时实现ActionListener(按钮监听)和MouseListener(鼠标监听),支持 “生产无人机 / 入侵者” 和 “鼠标点击生成任务” 两种交互。
(1)关键代码解析
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Random; public class DroneListener implements ActionListener, MouseListener { // 共享集合:无人机、入侵者、任务(与UI线程、其他线程共用) ArrayList<Drone> droneList; ArrayList<Intruder> intruderList; ArrayList<Task> taskList; Random random = new Random(); // 按钮监听逻辑(与V3一致,生产无人机/入侵者) public void actionPerformed(ActionEvent e) { String ac = e.getActionCommand(); if (ac.equals("生产无人机")) { int x = random.nextInt(700) + 200; int y = random.nextInt(500) + 175; int speedx = random.nextInt(5) - 2; int speedy = random.nextInt(5) - 2; droneList.add(new Drone(x, y, 0, speedx, speedy)); // 初始状态0:巡逻 } else if (ac.equals("生产入侵者")) { int x = random.nextInt(1200 - 205) + 60; int y = random.nextInt(950 - 205) + 60; // 确保入侵者初始在防守区外 while (true) { if (x < 200 || x > 900 || y < 175 || y > 675) { break; } x = random.nextInt(1200 - 205) + 60; y = random.nextInt(950 - 205) + 60; } int speedx = random.nextInt(5) - 2; int speedy = random.nextInt(5) - 2; intruderList.add(new Intruder(x, y, speedx, speedy, 45)); } } // 新增:鼠标按压时触发(生成任务) public void mousePressed(MouseEvent e) { // 获取鼠标点击的坐标(e.getX()=x,e.getY()=y) int x = e.getX(); int y = e.getY(); // 创建任务对象(状态0:未分配) Task task = new Task(x, y, 0); taskList.add(task); // 存入任务集合 System.out.println("生成任务,坐标:(" + x + "," + y + ")"); } // 以下4个方法是MouseListener接口必须重写的,无需实现逻辑,留空即可 public void mouseClicked(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} }(2)理解要点
鼠标监听使用:
- 接口实现:必须同时重写
MouseListener的 5 个方法,即使不用也不能删除(否则编译报错); - 坐标获取:
e.getX()和e.getY()获取的是鼠标在窗口内的坐标,直接用于创建任务点,精准对应点击位置; - 注册监听:需在
DroneUI中调用addMouseListener(droneL),否则鼠标点击无反应。
5.界面与线程协同 ——DroneUI(新增任务集合与线程)
DroneUI类新增任务集合(taskList)和任务处理线程(TaskProThread),并注册鼠标监听器,是整个项目的 “中枢调度中心”。
(1)关键代码解析
import javax.swing.*; import java.awt.*; import java.util.ArrayList; public class DroneUI extends JFrame { // 原有集合:无人机、入侵者 ArrayList<Drone> droneList = new ArrayList<>(); ArrayList<Intruder> intruderList = new ArrayList<>(); // 新增集合:任务 ArrayList<Task> taskList = new ArrayList<>(); public DroneUI() { // 窗口基础设置(与V3一致) setTitle("智能无人机平台"); setSize(1200, 1000); setDefaultCloseOperation(EXIT_ON_CLOSE); setLocationRelativeTo(null); // 按钮面板(与V3一致) JPanel btnPanel = new JPanel(); btnPanel.setBackground(Color.LIGHT_GRAY); JButton btn = new JButton("生产无人机"); JButton btn1 = new JButton("生产入侵者"); btnPanel.add(btn); btnPanel.add(btn1); add(btnPanel, BorderLayout.SOUTH); setVisible(true); // 初始化绘图工具、监听器、线程 Graphics g = this.getGraphics(); DroneThread dt = new DroneThread(g); // 无人机线程 DroneListener droneL = new DroneListener(); // 监听器(按钮+鼠标) TaskProThread tpt = new TaskProThread(); // 新增:任务处理线程 // 注册监听 btn.addActionListener(droneL); btn1.addActionListener(droneL); addMouseListener(droneL); // 新增:注册鼠标监听器 // 共享集合传递(关键!所有线程共用同一个集合) droneL.droneList = droneList; droneL.intruderList = intruderList; droneL.taskList = taskList; // 监听器获取任务集合 dt.droneList = droneList; dt.intruderList = intruderList; dt.taskList = taskList; // 无人机线程获取任务集合 tpt.droneList = droneList; // 任务线程获取无人机集合 tpt.taskList = taskList; // 任务线程获取任务集合 // 启动线程(两个线程并行工作) dt.start(); tpt.start(); // 新增:启动任务处理线程 } // 重写paint方法 public void paint(Graphics g) { super.paint(g); } public static void main(String[] args) { new DroneUI(); } }(2)理解要点
多线程协同:
- 两个线程并行:
DroneThread负责绘制和对抗,TaskProThread负责任务分配,通过共享集合通信,互不干扰; - 集合传递:必须将
taskList传递给监听器(生成任务)、无人机线程(绘制任务)、任务线程(分配任务),否则功能失效。
6.敌对实体类优化——Intruder(边界调整 + 生命值可视化)
V4 版本的Intruder类优化了边界判断,新增生命值可视化(新手能看到入侵者剩余血量)。
(1)关键代码解析
import java.awt.Graphics; import java.awt.Color; public class Intruder { // 入侵者属性 int x, y; // 坐标 int speedx, speedy; // 速度 int size; // 尺寸 int blood; // 生命值 // 构造方法:初始化坐标、速度、尺寸、生命值 public Intruder(int x, int y, int speedx, int speedy, int size) { this.x = x; this.y = y; this.speedx = speedx; this.speedy = speedy; this.size = size; this.blood = 100; // 初始生命值100 } // 行为1:绘制入侵者 public void drawIntruder(Graphics g) { if (blood <= 0) { // 生命值≤0时,不绘制 return; } g.setColor(Color.BLACK); // 主体黑色 g.fillOval(x, y, size, size); // 绘制黑色椭圆 g.setColor(Color.RED); // 边框红色 g.drawOval(x - 1, y - 1, size + 2, size + 2); // 绘制红色边框 } // 行为2:入侵者移动 public void move() { if (blood <= 0) { return; } // 边界调整:左60,右1200-145,上60,下950-145(扩大运动范围,预留安全距离) if (x > 1200 - 145 || x < 60) { speedx = -speedx; } if (y > 950 - 145 || y < 60) { speedy = -speedy; } x += speedx; y += speedy; } // 生命值可视化(在DroneThread的入侵者扫描逻辑中添加) g.setColor(Color.BLACK); // 绘制生命值背景框(入侵者上方) g.drawRect(intruder.x, intruder.y - 22, 20, 10); g.setColor(Color.GREEN); // 绘制当前生命值(按比例填充绿色) g.fillRect(intruder.x + 1, intruder.y - 21, (int)(intruder.blood / 100.0 * 20), 8); g.setColor(Color.RED); // 绘制生命值数字(直观显示) g.drawString("" + intruder.blood, intruder.x + 18, intruder.y); }(2)理解要点
生命值可视化:
- 背景框 + 填充条:黑色边框是生命值满格的宽度(20 像素),绿色填充条长度随
blood比例变化(如 blood=50 时,填充 10 像素); - 数字显示:直接绘制
blood值,新手无需计算,一眼就能看到入侵者剩余血量。
四、常见问题与注意事项(新手避坑)
1. 鼠标点击不生成任务
- 原因 1:未给窗口注册鼠标监听器(忘记
addMouseListener(droneL)); - 原因 2:
mousePressed方法名写错(如写成mousePress); - 解决:检查监听器注册代码和方法名拼写,确保
MouseListener的 5 个方法都重写。
2. 任务分配给忙碌的无人机
- 原因:任务分配时未过滤状态(
if (d.state == 1 || d.state == 2)),导致分配给正在跟随 / 处理任务的无人机; - 解决:确保遍历无人机时,跳过
state=1和state=2的无人机,只选择state=0的空闲无人机。
3. 无人机不飞向任务点
- 原因 1:速度调整逻辑错误(如
dx>0时设为-baseSpeedX,方向相反); - 原因 2:
runSpeedx/y未正确赋值,仍使用默认速度; - 解决:检查速度调整代码,确保
dx>0时runSpeedx=baseSpeedX,dx<0时为-baseSpeedX。
4. 任务完成后无人机不回归巡逻
- 原因:任务生命值≤0 时,未将无人机
state重置为 0; - 解决:在
TaskProThread的任务监控逻辑中,添加d.state = 0(任务完成后重置状态)。
5. 数组下标越界(任务集合)
- 原因:任务完成后未判断
taskList是否为空,直接调用taskList.get(d.tindex); - 解决:在遍历无人机处理任务前,添加
if (taskList.size() == 0) continue;,避免空集合访问。
五、拓展巩固
1. 实现补给仓功能(文档提到的电量 / 弹药补给)
- 需求:添加 “补给仓” 按钮,点击生成补给点,无人机靠近后恢复电量 / 弹药;
- 步骤:
- 新增
Supply类(属性:x、y、type,方法:draw); - 监听器添加 “生成补给仓” 按钮逻辑,创建
Supply对象存入supplyList; - 无人机线程中,遍历
supplyList,无人机靠近补给点时,恢复电量 / 弹药; - 补给点被使用后,从
supplyList中移除。
- 新增
2. 任务优先级设置
- 需求:给任务添加优先级(1~3 级),高优先级任务优先分配无人机;
- 思路:
Task类新增priority属性(1 = 低,2 = 中,3 = 高);- 鼠标点击时,按快捷键区分优先级(如按住 Ctrl 点击生成 3 级任务);
TaskProThread中,先遍历高优先级任务,再处理中、低优先级。
3. 多任务并行处理
- 需求:支持同时分配多个任务,每个任务分配一个空闲无人机;
- 思路:修改
TaskProThread的任务分配逻辑,遍历所有未分配任务,为每个任务分别匹配最近的空闲无人机(避免一个无人机同时处理多个任务)。
4. 任务超时机制
- 需求:任务生成后 30 秒未完成,自动标记为 “失败” 并重置;
- 思路:
Task类新增createTime属性(记录生成时间),TaskProThread中判断当前时间与createTime的差值,超过 30 秒则重置任务状态。
六、总结
V4 版本完成了从 “单纯对抗” 到 “任务 + 对抗” 的复合场景升级,核心收获如下:
- 交互能力升级:掌握
MouseListener实现鼠标交互,理解 “用户操作→事件触发→逻辑执行” 的完整链路; - 多线程协作:学会多个线程(无人机线程 + 任务线程)通过共享集合通信,避免线程冲突;
- 状态机思维:理解 “状态决定行为” 的设计模式,能通过状态切换实现复杂功能(巡逻→跟随→任务);
- 数学逻辑落地:将勾股定理等数学知识应用到距离计算中,明白 “代码解决实际问题” 的思路;
- 可视化优化:通过颜色、图形、数字直观展示状态和数据(如无人机状态灯、入侵者生命值),提升项目可读性。
对于 Java 新手,V4 版本的学习重点是 “模块拆分” 和 “逻辑协同”—— 复杂项目并非一蹴而就,而是将 “任务生成”“任务分配”“状态管理”“对抗逻辑” 拆分为多个模块,每个模块负责单一功能,再通过共享数据和线程协作整合。通过本项目,你不仅巩固了多线程、集合、Swing 等基础,还培养了 “需求拆解→代码实现→优化迭代” 的编程思维,为后续开发更复杂的 Java 应用(如管理系统、小游戏)奠定了坚实基础。