从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面

本文主要是介绍从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  本章主要实现注册登陆功能和游戏的主界面。有了游戏的界面,大家能有更直观的认识。

  本章我们主要开发的是idlewow-game模块,其实就是游戏的客户端展示层。因为是放置游戏,为了方便,主要使用spring-mvc来开发,整个游戏形式是类似web端的文字mud游戏,会稍带一些图形图片。当然,游戏的客户端可以是多种多样的,也可以使用U3D开发成移动端或者C++/flash/silver light,开发成PC端、网页端、微端等等形式,但需要更多的美术资源。

一、注册登陆和角色创建

  首先,我们把idlewow-game的框架搭建好,因为也是spring-mvc项目,可以基本参照前面的rms模块。各种配置,这里就不再赘述了。可以先把源代码下载下来,对照着看。

  一)添加jsp页面

  为了便于理解,这里我们先添加个首页,即登陆页面。其实就是一个背景图,带上登陆输入框和注册、登陆按钮。如下图,是我从网上随便找的一个背景图。这里,注册和登陆页面的展示,不需要经过controller做什么处理,直接在"/webapp/"目录下添加jsp页面即可。代码如下,比较简单,注意里面引用的css和js就不粘贴了。

www.wityx.com www.wityx.com
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% String path = request.getContextPath();%>
<html>
<head><title>挂机魔兽</title><link rel="stylesheet" href="<%=path%>/css/wow/base.css?v=0714"><script type="text/javascript" src="/js/jquery.min.js"></script><style>.input-wow {background: rgb(80, 80, 80);border: gray;border-radius: 4px;color: white;}</style>
</head>
<body>
<div class="bg bg-index"></div>
<div style="text-align:center; width:100%;position:relative;top:58%;"><form id="form-login" method="post"><div style="margin: 10px;"><input type="text" name="username" placeholder="请输入账号" class="input-wow"/></div><div style="margin-top: 50px;"><input type="password" name="password" placeholder="请输入密码" class="input-wow"/></div><div style="margin: 20px;"><button type="button" class="btn-wow" onclick="login();">登 陆</button><button type="button" class="btn-wow" onclick="location.href='/register.jsp';">注 册</button></div></form>
</div>
<script type="text/javascript" src="<%=path%>/js/wow/index.js?v=0714"></script>
</body>
</html>
index.jsp
www.wityx.com www.wityx.com
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>注册账号</title><script type="text/javascript" src="/js/jquery.min.js"></script>
</head>
<body>
<form id="form-register" method="post"><div><label>账号:</label><input type="text" name="username" id="username"/></div><div><label>密码:</label><input type="password" name="password" id="password"/></div><div><label>确认密码:</label><input type="password" name="password2" id="password2"/></div><div><button type="button" onclick="register();">注册</button><button type="button" onclick="history.go(-1);">返回</button></div>
</form>
<script type="text/javascript" src="/js/wow/register.js"></script>
</body>
</html>
register.jsp

  好了,现在页面有了,接下来,在注册页面点击“注册”和登陆页面点击“登陆”按钮时,就需要controller来做后台逻辑处理了。

 二)hessian客户端配置

  在添加controller前,我们先把hessian客户端配置好。注意,在调用hessian接口的客户端,同样需要在pom中引用hessian的包。

  因为game模块作为游戏的客户端展示层,本身不访问底层 数据库,这里就需要调用上一章提供的hessian服务,来完成注册和登陆功能。hessian的服务端配置上一章已经讲过了,在调用时,上一章我们直接使用代码生成代理类进行测试。实际使用时,一般只需要配置一个xml文件,就可以在项目中引用对应的对象。

  在game模块的"/resources/properties"目录下,添加 hessian.properties 文件,用来存放 hessian 服务的url地址,内容如下:

  server.url=http://localhost:20000

  再在"/resources/spring"目录下,添加 hessian-client.xml 文件,用来配置需要引用的接口地址(即hessian服务端暴露出的接口),内容如下:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd"><util:properties location="classpath:/properties/hessian.properties" id="hessian"/><bean id="userService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"><property name="serviceUrl" value="#{hessian['server.url']}/remoting/UserService"/><property name="serviceInterface" value="com.idlewow.user.service.UserService"/></bean><bean id="characterService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"><property name="serviceUrl" value="#{hessian['server.url']}/remoting/CharacterService"/><property name="serviceInterface" value="com.idlewow.character.service.CharacterService"/></bean>
</beans>

    然后,在spring的上下文配置文件 applicationContext.xml 中,将这段配置引入即可,即:

<beans>        ........<import resource="hessian-client.xml"/>........
</beans>

        全部配置完成,就可以在项目中引用并调用hessian服务了。注意,以后服务端每次添加新的接口,都需要在服务端和客户端的配置文件添加配置。

     三)添加controller

  页面完成后,点击“注册“和”登陆“按钮时,需要后台进行相应的逻辑处理,在spring-mvc框架下,就需要新建一个controller。

  在com.idlewow.game.controller包下,新建一个类GameController,内容如下:

www.wityx.com www.wityx.com
package com.idlewow.game.controller;import com.idlewow.character.model.Character;
import com.idlewow.character.service.CharacterService;
import com.idlewow.common.model.CommonResult;
import com.idlewow.game.GameWorld;
import com.idlewow.user.model.UserAccount;
import com.idlewow.user.service.UserService;
import com.idlewow.util.cipher.MD5Util;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.regex.Pattern;@Controller
@RequestMapping("/game")
public class GameController {private static final Logger logger = LogManager.getLogger(GameController.class);@AutowiredUserService userService;@AutowiredCharacterService characterService;@Autowiredprivate HttpSession httpSession;@Autowiredprivate HttpServletRequest request;@ResponseBody@RequestMapping("/register")public Object register(String username, String password) {String ip = request.getRemoteAddr();String regex = "[a-zA-Z0-9]{6,20}";if (!Pattern.matches(regex, username)) {return CommonResult.fail("用户名应为6-20位英文字母、数字");}if (!Pattern.matches(regex, password)) {return CommonResult.fail("密码应为6-20位英文字母、数字");}String cipher = MD5Util.md5(password);CommonResult commonResult = userService.register(username, cipher, ip);return commonResult;}@ResponseBody@RequestMapping(value = "/login", method = RequestMethod.POST)public Object login(String username, String password) {String cipher = MD5Util.md5(password);CommonResult commonResult = userService.login(username, cipher);if (commonResult.isSuccess()) {UserAccount userAccount = (UserAccount) commonResult.getData();httpSession.setAttribute(GameWorld.SK_User, userAccount);}return commonResult;}@RequestMapping("/characters")public Object characterList(RedirectAttributes redirectAttributes) {try {UserAccount userAccount = (UserAccount) httpSession.getAttribute(GameWorld.SK_User);String userId = userAccount.getId();CommonResult commonResult = characterService.getUserCharacters(userId);if (!commonResult.isSuccess()) {throw new Exception("获取角色列表失败!" + commonResult.getMessage());}List<Character> list = (List<Character>) commonResult.getData();request.setAttribute("characters", list);return "/game/characters";} catch (Exception ex) {redirectAttributes.addFlashAttribute("error", ex.getMessage());return "redirect:/game/error";}}@RequestMapping("/createChar")public Object createChar() {return "/game/createChar";}@ResponseBody@RequestMapping(value = "/createChar", method = RequestMethod.POST)public Object createChar(String name, Integer faction, Integer race, Integer job) {UserAccount userAccount = (UserAccount) httpSession.getAttribute(GameWorld.SK_User);String userId = userAccount.getId();if (StringUtils.isBlank(name)) {return CommonResult.fail("角色昵称不能为空!");}if (name.length() < 2 || name.length() > 10) {return CommonResult.fail("角色昵称应为 2-10 个字符!");}String pattern = "^[\\u4e00-\\u9fa5_a-zA-Z0-9]+$";if (!Pattern.matches(pattern, name)) {return CommonResult.fail("角色名称只能包含汉字、英文字母、数字、下划线!");}if (faction == null) {return CommonResult.fail("请选择阵营!");}if (race == null) {return CommonResult.fail("请选择种族!");}if (job == null) {return CommonResult.fail("请选择职业!");}CommonResult commonResult = characterService.createCharacter(userId, name, faction, race, job);return commonResult;}@RequestMapping("/main")public Object main(String characterId, RedirectAttributes redirectAttributes) {if (characterId == null) {characterId = httpSession.getAttribute(GameWorld.SK_CharId).toString();}CommonResult commonResult = characterService.find(characterId);if (commonResult.isSuccess()) {Character character = (Character) commonResult.getData();httpSession.setAttribute(GameWorld.SK_CharId, characterId);request.setAttribute("character", character);return "/game/main";} else {redirectAttributes.addFlashAttribute("error", commonResult.getMessage());return "redirect:/game/error";}}@RequestMapping("/error")public Object error() {return "/game/error";}
}
GameController

  其中,userService和characterService就是对hessian接口的引用。这里注解使用@Autowired或者@Resource均可。具体区别可以百度一下。

    @AutowiredUserService userService;@AutowiredCharacterService characterService;

  controller中的方法,对应提供了“注册”、“登陆”、“获取角色列表”、“创建角色”、“进入游戏主界面”、“错误页面”几个功能。其中,还需要对应的创建几个页面,目录结构如下图。页面代码就不粘贴了,可以下载源码查看。这里需要注意的是,由controller路由的页面,根目录是"/WEB-INF/views/”,这是我们在spring-mvc.xml中的视图解析节点配置的,属于mvc的路由机制。而前面的index.jsp和register.jsp,是直接从文件目录结构访问的,未参与mvc路由。

 四)数据库设计

  项目中用到的sql建表语句等,都在idlewow-doc目录下。这里账号表和角色表比较简单,sql里也有相应的注释。这里需要注意的是,角色表 user_character 中,有一个字段 extra_info。这个字段主要以json文本的形式存储一些缓存数据。比如角色身上的装备信息,角色所在的地图,等等等等。

  试想一下,在游戏世界中,一个角色可能会频繁的进行更换装备、切换地图等操作,这些信息都需要记录。如果游戏中每个角色有此类动作时,都进行更新写库,对数据库会造成巨大的压力。因此这部分数据,会在游戏一开始时,读取到缓存中(比如 redis)。在游戏进行时,只需要更新缓存数据。在游戏退出时,再将缓存中的数据写回数据库。

二、效果演示

小结

  本章主要实现了游戏的主界面,但界面上的角色信息、战斗记录、地图信息及怪物信息等,目前都是静态文本,接下来只要一点点往上添加就行了。

  本章的代码可能会有部分冗余,因为是从我已经开发好的分支上,直接拷贝过来的。有些代码可能目前还用不到,或者后期会有改进,有些地方是我还没想好最终会怎么做还在思考。看代码的时候,重点关注本章需要实现的内容就可以了,有些不合理的地方也可以自己发挥。

  源码下载地址:https://545c.com/file/14960372-403554557

  本文原文地址:https://www.cnblogs.com/lyosaki88/p/idlewow_11.html

  项目交流群:329989095 

这篇关于从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/986959

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的