3 Commits
68588a38a5
...
238532aa96
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
238532aa96 |
Merge remote-tracking branch 'origin/milestone-20260325-学习笔记' into milestone-20260325-学习笔记
|
1 week ago |
|
|
9317205c12 |
Merge branch 'libolin/feature-20260327153128-学习笔记' into milestone-20260325-学习笔记
|
1 week ago |
|
|
c9a00bc88f |
4.4
|
1 week ago |
1 changed files with 302 additions and 0 deletions
-
302李柏霖学习笔记/4.4.md
@ -0,0 +1,302 @@ |
|||||
|
练手项目:java地牢 |
||||
|
|
||||
|
dungeon-boot/ |
||||
|
├── src/ |
||||
|
│ ├── main/ |
||||
|
│ │ ├── java/ |
||||
|
│ │ │ └── com/dungeon/ |
||||
|
│ │ │ ├── DungeonApplication.java // 项目启动类 |
||||
|
│ │ │ ├── common/ // 公共配置与工具 |
||||
|
│ │ │ │ ├── config/ // MyBatis-Plus/Redis 配置 |
||||
|
│ │ │ │ ├── exception/ // 自定义异常(如:玩家死亡异常) |
||||
|
│ │ │ │ └── result/ // 统一接口返回对象 (Result<T>) |
||||
|
│ │ │ ├── controller/ // API 控制层 (与前端交互) |
||||
|
│ │ │ │ ├── PlayerController.java |
||||
|
│ │ │ │ └── GameController.java |
||||
|
│ │ │ ├── entity/ // 数据库映射实体 (POJO) |
||||
|
│ │ │ │ ├── Player.java |
||||
|
│ │ │ │ ├── Room.java |
||||
|
│ │ │ │ └── Monster.java |
||||
|
│ │ │ ├── mapper/ // MyBatis-Plus Mapper 接口 |
||||
|
│ │ │ │ ├── PlayerMapper.java |
||||
|
│ │ │ │ └── RoomMapper.java |
||||
|
│ │ │ └── service/ // 核心业务逻辑层 |
||||
|
│ │ │ ├── PlayerService.java // 玩家属性、升级逻辑 |
||||
|
│ │ │ ├── MapService.java // 移动、房间探索逻辑 |
||||
|
│ │ │ └── BattleService.java // 战斗计算逻辑 |
||||
|
│ │ └── resources/ |
||||
|
│ │ ├── application.yml // 数据库连接与游戏全局配置 |
||||
|
│ └── test/ // 单元测试 |
||||
|
└── pom.xml // 项目依赖管理 |
||||
|
|
||||
|
controller |
||||
|
|
||||
|
```java |
||||
|
package com.example.demo01.controller; |
||||
|
|
||||
|
import com.example.demo01.common.result.Result; |
||||
|
import com.example.demo01.entity.Player; |
||||
|
import com.example.demo01.entity.Room; |
||||
|
import com.example.demo01.service.BattleService; |
||||
|
import com.example.demo01.service.MapService; |
||||
|
import com.example.demo01.service.PlayerService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/api/game") |
||||
|
public class GameController { |
||||
|
|
||||
|
@Autowired |
||||
|
private PlayerService playerService; |
||||
|
|
||||
|
@Autowired |
||||
|
private MapService mapService; |
||||
|
|
||||
|
@Autowired |
||||
|
private BattleService battleService; |
||||
|
|
||||
|
@PostMapping("/move") |
||||
|
public Result<Room> move(@RequestBody MoveRequest request) { |
||||
|
// 1. 获取玩家信息 |
||||
|
Player player = playerService.getPlayerStatus(request.getPlayerId()); |
||||
|
if (player == null) return Result.error("玩家不存在"); |
||||
|
|
||||
|
// 2. 调用地图服务判断是否可以移动 |
||||
|
Room nextRoom = mapService.move(player.getCurrentRoomId(), request.getDirection()); |
||||
|
|
||||
|
if (nextRoom != null) { |
||||
|
// 3. 移动成功,更新玩家所在的房间ID |
||||
|
playerService.moveToRoom(player.getId(), nextRoom.getId()); |
||||
|
// 返回新房间的信息,让前端显示描述文字 |
||||
|
return Result.success(nextRoom); |
||||
|
} else { |
||||
|
return Result.error("哎呀!你撞到了墙上,那里没有路。"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/attack") |
||||
|
public Result<BattleResult> doAttack(@RequestParam Long playerId, @RequestParam Long monsterId) { |
||||
|
BattleResult result = battleService.attack(playerId, monsterId); |
||||
|
return Result.success(result); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
``` |
||||
|
@Data |
||||
|
public class MoveRequest { |
||||
|
/** |
||||
|
* 正在操作的玩家 ID |
||||
|
*/ |
||||
|
private Long playerId; |
||||
|
|
||||
|
/** |
||||
|
* 移动方向:north, south, east, west |
||||
|
*/ |
||||
|
private String direction; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
``` |
||||
|
@RestController |
||||
|
@RequestMapping("/api/player") |
||||
|
public class PlayerController { |
||||
|
|
||||
|
@Autowired |
||||
|
private PlayerService playerService; |
||||
|
|
||||
|
// 获取玩家当前面板状态:GET /api/player/status?id=1 |
||||
|
@GetMapping("/status") |
||||
|
public Result<Player> getStatus(@RequestParam Long id) { |
||||
|
Player player = playerService.getPlayerStatus(id); |
||||
|
if (player == null) { |
||||
|
return Result.error("未找到该角色"); |
||||
|
} |
||||
|
return Result.success(player); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
service |
||||
|
|
||||
|
``` |
||||
|
package com.example.demo01.service.impl; |
||||
|
|
||||
|
import com.example.demo01.controller.BattleResult; |
||||
|
import com.example.demo01.entity.Monster; |
||||
|
import com.example.demo01.entity.Player; |
||||
|
import com.example.demo01.mapper.MonsterMapper; |
||||
|
import com.example.demo01.mapper.PlayerMapper; |
||||
|
import com.example.demo01.service.BattleService; |
||||
|
import com.example.demo01.service.PlayerService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
@Service |
||||
|
public class BattleServiceImpl implements BattleService { |
||||
|
|
||||
|
@Autowired |
||||
|
private PlayerMapper playerMapper; |
||||
|
@Autowired |
||||
|
private MonsterMapper monsterMapper; |
||||
|
@Autowired |
||||
|
private PlayerService playerService; |
||||
|
|
||||
|
@Override |
||||
|
@Transactional |
||||
|
public BattleResult attack(Long playerId, Long monsterId) { |
||||
|
Player player = playerMapper.selectById(playerId); |
||||
|
Monster monster = monsterMapper.selectById(monsterId); |
||||
|
|
||||
|
StringBuilder log = new StringBuilder(); |
||||
|
|
||||
|
// 1. 玩家攻击怪物 |
||||
|
// 伤害公式:攻击力 - 防御力(最小为1) |
||||
|
int damageToMonster = Math.max(1, player.getAtk() - monster.getDef()); |
||||
|
monster.setHp(Math.max(0, monster.getHp() - damageToMonster)); |
||||
|
log.append(String.format("你攻击了 %s,造成了 %d 点伤害。 ", monster.getName(), damageToMonster)); |
||||
|
|
||||
|
// 2. 检查怪物是否死亡 |
||||
|
if (!monster.isAlive()) { |
||||
|
log.append(String.format("%s 倒下了!你获得了 %d 经验。", monster.getName(), monster.getExpReward())); |
||||
|
// 结算奖励 |
||||
|
playerService.addRewards(playerId, monster.getExpReward(), monster.getGoldReward()); |
||||
|
// 从房间移除怪物(可选逻辑:更新Room表或者标记Monster已死) |
||||
|
monsterMapper.deleteById(monsterId); |
||||
|
|
||||
|
return BattleResult.builder() |
||||
|
.log(log.toString()).monsterHp(0).playerHp(player.getHp()) |
||||
|
.monsterDead(true).rewardsExp(monster.getExpReward()).build(); |
||||
|
} |
||||
|
|
||||
|
// 3. 怪物反击(如果还没死) |
||||
|
int damageToPlayer = Math.max(1, monster.getAtk() - 5); // 假设玩家基础防御5 |
||||
|
player.setHp(Math.max(0, player.getHp() - damageToPlayer)); |
||||
|
playerMapper.updateById(player); // 更新玩家血量 |
||||
|
monsterMapper.updateById(monster); // 更新怪物血量 |
||||
|
|
||||
|
log.append(String.format("%s 发起反击,你受到了 %d 点伤害。", monster.getName(), damageToPlayer)); |
||||
|
|
||||
|
return BattleResult.builder() |
||||
|
.log(log.toString()) |
||||
|
.playerHp(player.getHp()) |
||||
|
.monsterHp(monster.getHp()) |
||||
|
.playerDead(player.getHp() <= 0) |
||||
|
.build(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
``` |
||||
|
package com.example.demo01.service.impl; |
||||
|
|
||||
|
import com.example.demo01.entity.Room; |
||||
|
import com.example.demo01.mapper.RoomMapper; |
||||
|
import com.example.demo01.service.MapService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
@Service |
||||
|
public class MapServiceImpl implements MapService { |
||||
|
|
||||
|
@Autowired |
||||
|
private RoomMapper roomMapper; |
||||
|
|
||||
|
@Override |
||||
|
public Room move(Long currentRoomId, String direction) { |
||||
|
// 1. 先找到玩家所在的当前房间 |
||||
|
Room currentRoom = roomMapper.selectById(currentRoomId); |
||||
|
if (currentRoom == null) return null; |
||||
|
|
||||
|
// 2. 根据方向获取目标房间的 ID |
||||
|
Long nextRoomId = null; |
||||
|
switch (direction.toLowerCase()) { |
||||
|
case "north": nextRoomId = currentRoom.getNorthRoomId(); break; |
||||
|
case "south": nextRoomId = currentRoom.getSouthRoomId(); break; |
||||
|
case "east": nextRoomId = currentRoom.getEastRoomId(); break; |
||||
|
case "west": nextRoomId = currentRoom.getWestRoomId(); break; |
||||
|
} |
||||
|
|
||||
|
// 3. 如果 ID 为空,说明那边是墙 |
||||
|
if (nextRoomId == null) return null; |
||||
|
|
||||
|
// 4. 返回目标房间的完整信息 |
||||
|
return roomMapper.selectById(nextRoomId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Room getRoomById(Long roomId) { |
||||
|
return roomMapper.selectById(roomId); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
``` |
||||
|
package com.example.demo01.service.impl; |
||||
|
|
||||
|
import com.example.demo01.entity.Player; |
||||
|
import com.example.demo01.mapper.PlayerMapper; |
||||
|
import com.example.demo01.service.PlayerService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
@Service |
||||
|
public class PlayerServiceImpl implements PlayerService { |
||||
|
|
||||
|
@Autowired |
||||
|
private PlayerMapper playerMapper; |
||||
|
|
||||
|
@Override |
||||
|
public Player getPlayerStatus(Long playerId) { |
||||
|
return playerMapper.selectById(playerId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional // 涉及数据库修改,建议开启事务 |
||||
|
public boolean moveToRoom(Long playerId, Long newRoomId) { |
||||
|
Player player = playerMapper.selectById(playerId); |
||||
|
if (player == null) return false; |
||||
|
|
||||
|
player.setCurrentRoomId(newRoomId); |
||||
|
return playerMapper.updateById(player) > 0; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void takeDamage(Long playerId, Integer damage) { |
||||
|
Player player = playerMapper.selectById(playerId); |
||||
|
if (player != null) { |
||||
|
// 计算扣血后的 HP,确保不小于 0 |
||||
|
int newHp = Math.max(0, player.getHp() - damage); |
||||
|
player.setHp(newHp); |
||||
|
playerMapper.updateById(player); |
||||
|
|
||||
|
if (newHp == 0) { |
||||
|
// 这里可以触发死亡逻辑,比如清空存档或传回出生点 |
||||
|
System.out.println("玩家 " + player.getName() + " 已阵亡!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void addRewards(Long playerId, Integer exp, Integer gold) { |
||||
|
Player player = playerMapper.selectById(playerId); |
||||
|
if (player != null) { |
||||
|
player.setExp(player.getExp() + exp); |
||||
|
// 简单的升级逻辑:每 100 经验升一级 |
||||
|
if (player.getExp() >= player.getLevel() * 100) { |
||||
|
player.setLevel(player.getLevel() + 1); |
||||
|
player.setAtk(player.getAtk() + 5); // 升级加攻击 |
||||
|
player.setHp(player.getMaxHp()); // 升级回满血 |
||||
|
} |
||||
|
playerMapper.updateById(player); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue