游戏物品管理系统
github: github.com/okfanger/xi…
@email: lovefyj616@foxmail.com
本管理系统可以存储同一类物品的数量,支持出售、使用、移除、购买等物品操作,此外还引入了个人的生命值、法力值、金币、攻击力的属性,用来展示该系统优秀的数据绑定操作。
例如,苹果的效果是 "法力值+10" ,点击使用后,该人物对应的生命值属性+10,同时与该属性绑定的红色进度条(血条)也会同步更新;点击购买炸弹时,系统会首先判断用户是否具有足够的金钱购买,并进行响应...
部署该系统时,需要导入项目依赖(在下文会提及),并将src目录里的sql文件导入到数据库中,修改数据库连接的配置文件,方可正常运行!
1. 项目依赖(包)及结构
1.1 项目依赖
javafx-sdk-11.0.2、mysql-connector-java-8.8.16、mybatis、log4j-1.2.17
1.2 项目结构
1.3 数据库结构
2. 类结构(UML图)
2.1 数据bean
用来数据的存储及fx组件之间的动态绑定
2.2 主界面
2.2.1 游戏主类 (Game.java)
2.2.2 商店类 (MarketStage.java)
2.2.3 登录(Login.java)、注册类(Register.java)
2.2.4 自定义面板类(TableViewPane.java、TopPane)
2.3 工具类 (连接数据库)
3. 数据的存储及读入、查询
所有数据库操作都以静态方法的形式在MyBatis中定义
3.2 引入MyBatis Factory 单例模式
3.2.1 配置数据库地址、用户名、密码
在项目 cn/akfang/advanture/mybatis/mybatis-config.xml 中,配置数据库信息
在property标签中,分别填写name为 url, username, password的标签
如下代码,表示 数据库地址为 本机(127.0.0.1),数据库名为 xiaofang ,用户名为 root,密码为 root
...
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1/xiaofang?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
...
3.2.2 单例模式
static {
System.out.println("MyBatis factory 初始化 ...");
// 静态代码块: 初始化 SqlSessionFactory 实例
try{
String resource = "./cn/akfang/advanture/mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
catch(Exception e)
{
e.printStackTrace();
}
}
3.3 在mapper.xml 中定义所有操作
这里篇幅有限,增删改查各选一个展示,详细请自行查看
<select id="checkUserExists" parameterType="hashmap" resultType="hashmap">
select * from `player_profile` where nick_name=#{nick_name};
</select>
<insert id="insertUser" parameterType="hashmap" useGeneratedKeys="true" keyProperty="player_id" >
INSERT INTO `player_profile` (`player_id`,`nick_name`,`password`,`registered_date`) VALUES (#{player_id},#{nick_name},#{password},#{registered_date});
</insert>
<update id="updatePlayerBoxItem" parameterType="hashmap" >
update `player_box` set `amount`=#{amount} where object_id=#{object_id}
</update>
<delete id="removeNullItemInPlayBox" parameterType="hashmap">
delete from player_box where object_id=#{object_id} and owner_id=#{owner_id}
</delete>
...
3.4 封装Sqlsession
所有session同样以静态方法的形式,存于MyBatis 类中
public static HashMap<Integer,HashMap<String,Object>> getObjectPropertyFromDatabase(){
HashMap<Integer,HashMap<String,Object>> objectProperty = new HashMap<>();
try (SqlSession session = MyBatis.factory.openSession()){
List<Map> resultList = session.selectList("getObjectClass");
resultList.forEach(item -> {
int key = (int) item.get("class_id");
HashMap<String,Object> value = new HashMap<>();
value.put("name",item.get("name"));
value.put("cost",item.get("cost"));
String[] effect = ((String)item.get("effect")).split(",");
for (String effects :effect){
String[] effectMap = effects.split(":");
value.put(effectMap[0],Integer.parseInt(effectMap[1]));
}
objectProperty.put(key,value);
});
}
return objectProperty;
}
public static void updatePlayerConditionHp(int player_id,int hp){
try (SqlSession session = MyBatis.factory.openSession()){
session.update("updatePlayerConditionHp",new HashMap<>(){{
put("player_id",player_id);
put("hp",hp);
}});
session.commit();
}
}
public static void updatePlayerConditionMoney(int player_id,int money){
try (SqlSession session = MyBatis.factory.openSession()){
session.update("updatePlayerConditionMoney",new HashMap<>(){{
put("player_id",player_id);
put("money",money);
}});
session.commit();
}
}
...
4. 布局
4.1 Game.java
4.2 TopPane.java
4.3 TableViewPane.java
4.4 Market.java
5. 部分关键操作演示
5.1 登录及注册
5.1.1 注册
点击注册按钮后,会向数据库提交一个select
try (SqlSession session = MyBatis.factory.openSession()){
List<Map> result = session.selectList(
"reg.checkUserExists",
new HashMap<>(){{
put("nick_name",tf[0].getText());
}}
);
...
}
若数据库中没有这个昵称的账号,就提交一个insert,并提交事务
if(result.size()!=1){
new Alert(Alert.AlertType.WARNING,"未找到对应的用户名").show();
} else {
String truePassword = (String) result.get(0).get("password");
if(truePassword.equals(pf.getText())){
thisStage.close();
new Game().begin(this.thisStage,result.get(0));
} else {
new Alert(Alert.AlertType.WARNING,"密码错误!").show();
}
}
5.1.2 登录
点击注册按钮后,会向数据库提交一个select
try (SqlSession session = MyBatis.factory.openSession()){
List<Map> result = session.selectList(
"reg.checkUserExists",
new HashMap<>(){{
put("nick_name",tf[0].getText());
}}
);
...
}
若数据库中没有这个昵称的账号,就弹出提示框
反之,将存有玩家数据的Map,传入Game.java,运行Game类的begin()方法
if(result.size()!=1){
new Alert(Alert.AlertType.WARNING,"未找到对应的用户名").show();
} else {
String truePassword = (String) result.get(0).get("password");
if(truePassword.equals(pf.getText())){
thisStage.close();
new Game().begin(this.thisStage,result.get(0));
} else {
new Alert(Alert.AlertType.WARNING,"密码错误!").show();
}
}
5.2 物品操作
5.2.1 物品使用
bt[0].setOnAction(event->{
if(thisItem.getAmount()==0){
return;
}
HashMap<String, Object> usage = Game.objectProperty.get(thisItem.getClassId());
for (String key : usage.keySet()) {
if (key.equals("attack")) player.setAttack(player.getAttack() + (Integer) usage.get("attack"));
if (key.equals("hp")) {
int after = player.getHp() + (Integer) usage.get("hp");
if (after < 0) {
new Alert(Alert.AlertType.WARNING, "生命值不足!").show();
return;
}
player.setHp(after);
}
if (key.equals("mp")) {
int after = player.getMp() + (Integer) usage.get("mp");
if (after < 0) {
new Alert(Alert.AlertType.WARNING, "法力值不足!").show();
return;
}
player.setMp(player.getMp() + (Integer) usage.get("mp"));
}
}
thisItem.setAmount(thisItem.getAmount() - 1);
//System.out.println(player.mpProperty().get());
});
5.2.2 物品出售
bt[1].setOnAction(event->{
if(thisItem.getAmount()==0){
return;
}
thisItem.setAmount(thisItem.getAmount()-1);
player.setMoney(player.getMoney()+thisItem.getCost());
});
5.2.4 物品移除
Button bt33 = new Button("移除");
this.setGraphic(bt33);
bt33.setOnAction(event->{
MyBatis.deleteNullItemInPlayerBox(thisItem.getId(),player.getPlayer_id());
data.remove(getIndex());
});
5.2.5 物品购买
buyButton.setOnAction(event->{
int money = player.getMoney();
if(money<thisItem.getCost()) return;
player.setMoney(player.getMoney()-thisItem.getCost());
GameObjectProperty result = checkPlayerBoxExists(thisItem.getClass_id());
if(result!=null){
result.setAmount(result.getAmount()+1);
//update
} else {
int feeback_id = MyBatis.insertItemInPlayerBox(player.getPlayer_id(),thisItem.getClass_id(),1);
//System.out.println(feeback_id);
playerbox.add(new GameObjectProperty(feeback_id,thisItem.getClass_id(),thisItem.getName(),thisItem.getCost(),1));
}
});
5.3 属性增减
5.3.1 血条增减
public void setHp(int hp) {
if(hp<0) return;
MyBatis.updatePlayerConditionHp(getPlayer_id(),hp);
this.hp.set(hp);
}
5.3.2 蓝条增减
public void setMp(int mp) {
if(mp<0) return;
MyBatis.updatePlayerConditionMp(getPlayer_id(),mp);
this.mp.set(mp);
}
5.3.3 金钱增减
public void setMoney(int money) {
if(money<0) return;
MyBatis.updatePlayerConditionMoney(getPlayer_id(),money);
this.money.set(money);
}