游戏开发总结-java篇

前言

Java语言,由于学习成本低,开发速度快,稳定性高,开源框架多,目前已成为网页游戏和手机游戏服务器开发的主要语言。从系统的开发流程简单梳理一下服务器开发需要用到的技术。

网络通信

这个是首要实现的,如果没有网络通信,就没有服务器存在的必要了。
网络通信就需要建立网络连接。目前网络通信有两种方式,

  • 一种是短连接 比如http,
  • 一种是长连接 比如socket
    当然http也是基于socket的,socket是通信的基础。所以要对tcp/ip通信的知识有所了解,明白通信的原理。
  • 基于这两种网络通信,游戏服务器也分为两种,弱联网和强联网。
    弱联网的游戏一般是指一些小型的游戏,比如开心消消乐,连连看,以及一些卡牌养成类游戏,这类游戏一般几秒钟或几分钟再会与服务器同步一次数据,一般会使用短连接。
    一些arpg游戏,实时战斗类游戏,以及带同屏显示玩家的游戏,这类游戏与服务器交互信息频繁,一秒钟可能几十次,会采用长连接,避免每次连接重新建立消耗系统资源,提高通信效率。

为了网络通信的效率,服务器要使用NIO(非阻塞网络通信)通信。它能支持大并发连接。
Java NIO是多路复用IO,在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。** 目前基于此技术有很多开源框架,最常用的有两种,Netty和Mina **

所以在网络通信这一块,如果是弱联网游戏,可以使用web那一套来开发游戏服务器,需要学习的技术一般有http原理,Json格式协议,servlet,Tomcat(也可以是其它web容器),spring等。
如果是强联网游戏,要学习的技术有Netty或Mina可以选择一种,多线程以及线程池的应用。这是网络通信所必须掌握的。只要能把客户端发送的信息接收到,并解析成代码使用的明文,就是成功了一半了,剩下的事就是把代码封装好,方便逻辑开发调用!

通信这块还要考虑消息的并发,长连接情况下,怎么处理断包,粘包问题,每个用户的消息处理的是不是有序的,如果有序会不会阻塞消息,如果无序会不会造成处理混乱,比如后到的消息先处理了,这些问题都要处理好,目前一般是保证同一个用户的消息要有序处理!

数据存储

网络通信调试好之后,不要急着做逻辑开发,还需要把数据如何存储理清楚!因为服务器端操作的全是数据,如果处理的不好,容易出bug,丢数据,这对游戏玩家来说是致命的,不可接受的!
数据存储要考虑:

  1. 数据如何存到数据库,是同步存储,还是异步存储!同步存储即将数操作完之后立刻写入数据库,异步操作即数据操作完之后先存储到内存缓存,然后由另外的线程或进程再同步到数据库!游戏中一般都是采用的异步存储方式,因为游戏并发量大,必须低延时,快速响应客户端!如果直接操作数据库太慢,会造成消息阻塞!内存缓存可先择的框架有redis,memcache,具体怎么同步到数据库,需要自己去设计了!
  2. 数据接口如何设计,能不能用工作生成这些数据操作的代码,能不能不用写SQL语句,需是封装在底层,或由工具生成。编程是门艺术,在这就体现出来了,当然是仁者见仁,智者见智了!
  3. 并发情况下数据的一致性,像这类可能多线程操作的数据,一般是放在内存中,由锁来控制并发!所以对锁的使用要熟悉,不要出现死锁,或锁粒度过大,造成线程的长时间等待的情况!
  4. 当数据量太大,一个数据库存储不了,数据该怎么分库分表!一种是水平划分,一种是垂直划分!具体的划分方式其它资料已有详细介绍,请自行查找阅读!目前有一个开源的分库框架mycat,是用JAVA写的,大家可以研究一下!

逻辑开发

逻辑开发就是实现游戏策划想象的各种游戏功能,比如,登录,物品使用,战斗结算等!逻辑开发代码量巨大,相互之间有很紧密的耦合性,所以每个功能模块一定要划分好!
最好是接触下单元测试,写之前考虑一下是否方便单元测试,这样设计的代码会更加清晰,每个方法责任明确,不容易出bug!
正是因为逻辑代码复杂,为了更好的管理代码,前辈们给我们总结了一些经验,就是著名的设计模式,所以学习一下设计模式对代码的管理有很大的好处!

逻辑开发一般遇到的问题有:

  1. 数据同步
    一说到数据同步或资源共享的时候,一般都会考虑到锁的使用。因为一份资源同时只能被一个线程访问才是安全的。Java的JDK中提供了一些锁,比如:synchronized,以及java.util.concurrent.lock包中的Lock对象,java.util.concurrent包中还提供了其它的一些原子操作的类,我们知道i++操作不是线程安全的,但是可以使用AtomicInteger中的getAndIncrement();方法代替,还有线程安全的ConcurrentHashMap哈稀Map。以及阻塞队列LinkedBlockingQueue等。都是逻辑开发中常用的处理数据同步的类。

  2. 设计模式的使用
    使用设计模式,可以让代码更加清晰,可扩展性更强,维护性更佳,比如,任务系统,任务会有很多种类型,要获得任务数据时,在一开始写这个系统的时候,我是这样写的if(type == 1)做什么,else if(type == 2)做什么,else if(type == 3)…else if(type == 35) else等。如果需要添加新的类型,又要添加else,这些if else都在同一个方法中。最后都不敢动一块,就怕出bug。其实当一个方法中出现三个以上的if else将来还可能增加时,就应当考虑设计是不是有问题了,后来改成责任链模式或状态模式,就解决了这个问题。还有一个例子是,当一个值变化,要影响多个任务完成状态时,可以使用观察者模式或监听模式或订阅模式去实现,这样功能之间完全解耦,出问题的机率会很小很小。

  3. 数据缓存框架的API使用
    目前主流使用的数据缓存框架有redis和memcache,虽然在逻辑开发前,主程会对这些进行一些封装,但是作为使用者还是需要对这些框架的客户端的使用要有所了解的。这些可以去阅读相关的文档。不是太难。

  4. 程序部署与运行
    目前,大多数Java项目都采用maven管理 ,可以使用maven打包开发好的程序,程序一般运行在远程服务器上,比如云服务器。一般运行Java程序的远程服务器都是Linux系统,需要使用Linux命令操作,或写一些shell脚本去自动化部署管理一些程序。

  5. 艰苦奋斗的精神
    首先,一定要让自己对这一行有兴趣,明确自己在这一行的技术选择,人生选择。很多人都知道,程序员加班是常有的事,坚持的住就做,坚持不了就再换一家公司做。

Java游戏服务器方面的开发要掌握的技术:

  1. 网络通信框架,Mina或Netty必须熟悉一种。而且自己必须要亲自搭建过,并明白其它原理。
  2. 通信协议制定和处理断包粘包,这一般属于网络通信框架要解决的问题。
  3. 数据缓存框架,redis或memcache选择一个,能熟练使用其客户端的命令。
  4. Java基础,Java NIO通信原理,Java集合的使用,Java多线程开发,Java锁的使用
  5. 了解一些设计模式。最好能把23种设计模式都看一遍,并结合自己的开发经验,看哪些可以用到设计模式,但也不能死套设计模式,要灵活运用。
  6. 熟悉使用Mysql数据库
  7. 了解数据库连接池的一些框架,比如Mybatis,hibernate
  8. 对Http协议熟悉,熟悉一种web容器,比如tomcat,了解其配置。
  9. 对常用的一些Linux命令要熟悉使用。
  10. 热爱学习,不断的充实自己,上面所说的只是入门技能而已,真正做起来要复杂的多,一定要让自己喜欢游戏这个行业,这样才能有动力做下去,做自己喜欢的工作还是比为了工作要好的!

java服务器目前主流框架技术

网络层netty或mina
数据协议protobuf
数据库mysql
缓存数据库redis jdbc一般是mybaits或者jpa
项目管理maven
设计层面spring
然后还需要熟悉多线程
linux的基本操作,git或者svn。

  • 9
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
推箱子是一种经典的游戏,它的玩法简单、规则清晰,受到了许多玩家的喜爱。在这论文中,我们将详细介绍推箱子游戏的实现过程,并呈现相应的Java代码。 一、推箱子游戏的规则 推箱子游戏的规则非常简单。玩家需要控制一个人物在一个有障碍物的场景中移动,并将所有的箱子推到指定的位置上。推箱子游戏的场景通常是一个方格子,玩家需要通过控制人物在这个方格子中移动,将所有的箱子推到指定的位置上,才能完成游戏。 在推箱子游戏中,玩家可以控制人物向上、向下、向左或向右移动。如果人物前面是一个箱子,那么就可以将箱子向着人物的移动方向推动。箱子只能在空地上推,不能推到墙或其他障碍物上。 二、推箱子游戏的实现 推箱子游戏的实现可以分为两个部分:场景的绘制和游戏逻辑的实现。下面我们将分别介绍这两个部分的实现过程。 1.场景的绘制 场景的绘制是推箱子游戏实现的第一步。在Java中,我们可以使用Swing来实现游戏界面的绘制。首先,我们需要创建一个JFrame对象,用来显示游戏界面。然后,再创建一个JPanel对象,用来作为游戏界面的背景。 在JPanel对象中,我们需要重写它的paintComponent方法,用来绘制游戏场景。在绘制场景的时候,我们可以使用一个二维数组来表示场景中的物体。例如,我们可以用0表示空地,1表示墙,2表示箱子,3表示目标位置,4表示人物等。 接下来,我们需要根据这个二维数组来绘制场景。我们可以使用Graphics对象来绘制场景中的每一个物体。例如,如果这个位置上是一个箱子,那么我们就可以使用Graphics对象画一个矩形,并填充成黄色,表示这是一个箱子。 2.游戏逻辑的实现 游戏逻辑的实现是推箱子游戏实现的第二步。在这一步中,我们需要实现游戏中的各种操作,例如人物的移动、箱子的移动等。 首先,我们需要在JPanel对象中添加KeyListener,用来监听键盘事件。在监听到键盘事件之后,我们需要对人物进行移动。如果人物前面是一个箱子,那么就需要将这个箱子向着人物的移动方向推动。 在实现箱子移动的时候,我们需要判断箱子的移动方向是否合法。如果箱子可以移动,那么就需要更新场景中箱子的位置,并重新绘制游戏界面。 在游戏的过程中,我们还需要判断当前是否已经完成了游戏。当所有的箱子都被推到目标位置上时,就表示游戏已经完成。 三、Java代码实现 下面是推箱子游戏Java代码实现。在这段代码中,我们使用了Swing来实现游戏界面的绘制,使用KeyListener来监听键盘事件,使用二维数组来表示游戏场景中的物体。 ```java import javax.swing.*; import java.awt.*; import java.awt.event.*; public class PushBoxGame extends JFrame implements KeyListener { private JPanel panel; // 游戏界面 private int[][] map; // 场景地图 private int rows, cols; // 场景行列数 private int px, py; // 人物坐标 private int boxCount; // 箱子数量 public PushBoxGame(int[][] map, int rows, int cols) { this.map = map; this.rows = rows; this.cols = cols; boxCount = countBoxes(); // 统计箱子数量 initUI(); // 初始化游戏界面 } private void initUI() { setTitle("推箱子游戏"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(600, 600); setLocationRelativeTo(null); panel = new JPanel() { @Override public void paintComponent(Graphics g) { super.paintComponent(g); drawMap(g); // 绘制游戏界面 } }; panel.setPreferredSize(new Dimension(rows * 50, cols * 50)); add(panel); addKeyListener(this); setFocusable(true); setVisible(true); } private void drawMap(Graphics g) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { switch (map[i][j]) { case 0: // 空地 g.setColor(Color.WHITE); break; case 1: // 墙 g.setColor(Color.BLACK); break; case 2: // 箱子 g.setColor(Color.YELLOW); break; case 3: // 目标位置 g.setColor(Color.RED); break; case 4: // 人物 g.setColor(Color.BLUE); break; } g.fillRect(j * 50, i * 50, 50, 50); // 绘制物体 } } } private int countBoxes() { int count = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (map[i][j] == 2) { count++; } } } return count; } private boolean isBox(int x, int y) { return map[x][y] == 2; // 判断是否是箱子 } private boolean isTarget(int x, int y) { return map[x][y] == 3; // 判断是否是目标位置 } private boolean isWall(int x, int y) { return map[x][y] == 1; // 判断是否是墙 } private boolean isCompleted() { int count = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (map[i][j] == 2 && isTarget(i, j)) { count++; } } } return count == boxCount; // 判断是否完成 } private void move(int dx, int dy) { int nx = px + dx, ny = py + dy; // 计算人物下一步的位置 if (isBox(nx, ny)) { // 如果前面是箱子 int bx = nx + dx, by = ny + dy; // 计算箱子下一步的位置 if (!isWall(bx, by) && !isBox(bx, by)) { // 如果箱子可以移动 map[px][py] = 0; // 清除原来的位置 map[nx][ny] = 4; // 更新人物位置 map[bx][by] = 2; // 更新箱子位置 px = nx; // 更新人物坐标 py = ny; } } else if (!isWall(nx, ny)) { // 如果前面是空地或目标位置 map[px][py] = 0; // 清除原来的位置 map[nx][ny] = 4; // 更新人物位置 px = nx; // 更新人物坐标 py = ny; } if (isCompleted()) { // 如果完成了游戏 JOptionPane.showMessageDialog(this, "恭喜你,完成了游戏!"); dispose(); // 关闭游戏窗口 } else { panel.repaint(); // 重新绘制游戏界面 } } @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_UP: move(-1, 0); break; case KeyEvent.VK_DOWN: move(1, 0); break; case KeyEvent.VK_LEFT: move(0, -1); break; case KeyEvent.VK_RIGHT: move(0, 1); break; } } @Override public void keyTyped(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) {} } ``` 四、总结 推箱子游戏是一种非常经典的游戏,它的实现过程相对简单,但需要掌握一定的编程技巧。在本文中,我们介绍了推箱子游戏的规则和Java代码实现过程。通过学习本文,相信读者可以更好地理解推箱子游戏的实现原理,也可以为后续的游戏开发提供一些参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值