用Java实现一个游戏角色绘制的动画类
用Java实现游戏角色的动画播放
- 前言
- 动图绘制类Animation
- 基本思想
- 实现
- 加载图片`loadImage()`
- 获取下一帧`getNextFrame()`
- 绘制动图`drawNextFrame()`
- 绘制镜面动图`drawFilpFrame()`
- 使用方法
- 测试
- 总结
- 整体代码
前言
前段时间做课设,小组决定做一个小游戏,中间的细枝末节就不在这里说了,其中一个任务就是设计一个依附于游戏角色的类——动图绘制类。
动图绘制类Animation
基本思想
根据组长的类图设计,游戏角色的绘制由Animation类负责。
初始化游戏角色的时候让角色的Animation类通过loadImage()
方法加载该角色的动图图片集合,当需要绘制的时候,就利用getNextFrame()
一张一张取出来,通过drawNextFrame()
方法绘制到面板上
实现
加载图片loadImage()
首先准备一组图片,图片我默认放在根目录下,这样写路径的时候就方便一些,人物用的是《明日方舟》的炎客(暴露了自己是一名刀塔客哈哈哈)
加载代码如下,我使用的是ImageIcon
,这里面的路径的读取方式和图片的存储格式也可以根据自己需要修改。
/*** 加载图片集合* @param path 图片集的文件夹路径+‘/’* @param num 图片个数*/public void loadImages(String path,int num) {String index = "";//循环把图片读进集合for(int i=1;i<num;i++) {if(i<10) {index = "0"+i;}else {index = String.valueOf(i);}ImageIcon icon = new ImageIcon(path+index+".png");m_images.add(icon.getImage());}}
获取下一帧getNextFrame()
这个就无需多言啦,只需要每次把图片集合的索引m_curFrameIndex
+1,然后返回图片即可。
public Image getNextFrame() {//索引+1(注意集合的范围)m_curFrameIndex = (m_curFrameIndex +1)%m_images.size();return (Image)m_images.elementAt(m_curFrameIndex);
}
绘制动图drawNextFrame()
首先得到集合里要绘制的图片,然后再获取绘制面板和画图设备,这里使用的是Graphics2D
,相比较Graphics
,Graphics2D
扩展了对几何形状、坐标转换、颜色管理和文本布局等更为复杂的控制。这样以后的一些图片处理就方便了。
public void drawNextFrame(Graphics g,int x,int y,JFrame panel) {//得到需要绘制的图片Image img = this.getNextFrame();//得到面板和画图设备buffer = panel.createImage(panel.getWidth(),panel.getHeight());m_og = (Graphics2D) buffer.getGraphics();//双缓冲绘制图片if(img != null) {m_og.drawImage(img,x,y,panel);g.drawImage(buffer,0,0,null);}}
绘制镜面动图drawFilpFrame()
我之前查阅的一些资料中,游戏角色同时拥有各个方向的图片,当发生转向时直接绘制相应方向的图片。
不过在Animation这里,尝试只用一套图片来绘制左右方向——反方向的绘制通过对图片进行对称变换来实现。
这时候Graphics2D
的用处就来了!
因为Graphics2D
包含一个AffineTransform
类,它类似于一个变换矩阵,可以使用一系列平移 (translation)、缩放 (scale)、翻转 (flip)、旋转 (rotation) 和错切 (shear) 来构造 仿射变换。
关于AffineTransform的使用我是参考这个博客:
Java中利用AffineTransform中的scale函数对图像进行对称变换
所以,需要绘制反向时,对图片进行一次对称变换即可。
//矩阵
AffineTransform trans = new AffineTransform();
//根据y轴对称
trans.scale(-1, 1);
//因为是针对整个面板对称所以要平移回去
trans.translate(-(2*x+img.getWidth(null)), 0);
//为Graphics2D设备设置变换矩阵
m_og.setTransform(trans);
使用方法
游戏角色一般会有多种状态(静止、行走、攻击等),每个状态对应一个Animation。
注意:这里的角色状态
CharacterState
类和角色方向Orientation
类是自定义类,里面定义的是状态常量以及方向常量,读者也可自行设计。
//角色的状态
public enum CharacterState{MOVE, //行走ATTACK, //攻击DIE, //死亡IDLE, //闲置,即站着不动WAIT //等待上场
}//角色的方向
public enum Orientation {EAST,//右SOUTH,//下WEST,//左NORTH//上
}
角色绘制由Character
的draw()
方法绘制自己,而draw()
方法又t通过自身状态把绘制任务交给不同的Animation
(连环甩锅XD)
public class Character {/*……其他属性省略……*///角色状态static CharacterState m_state;//方向static Orientation m_direction;// 动画绘制工具:有 攻击、闲置、死亡……private Animation m_aniATK; private Animation m_aniIDLE;private Animation m_aniDIE;//………………//根据不同的状态绘制public void draw(Graphics g,int x,int y,JFrame panel) {switch(m_state) {case ATTACK://攻击if(this.m_direction == Orientation.EAST)//默认向右m_aniATK.drawNextFrame(g, x, y, panel);elsem_aniATK.drawFilpFrame(g, x, y, panel);break;case IDLE://静止if(this.m_direction == Orientation.EAST)m_aniIDLE.drawNextFrame(g, x, y, panel);elsem_aniIDLE.drawFilpFrame(g, x, y, panel);break;case DIE://死亡if(this.m_direction == Orientation.EAST)m_aniDIE.drawNextFrame(g, x, y, panel);elsem_aniDIE.drawFilpFrame(g, x, y, panel);break;}}
测试
测试比较粗暴,直接让角色继承JFrame
类方便初始化,主函数通过一个while循环不停绘制来检验是否绘制成功。
//Character类的初始化函数
public void init() {//初始化图片集合(这里仅初始化攻击状态)m_aniATK = new Animation();m_aniATK.loadImages("Test/", 22); //载入攻击图片集合//初始化状态和方向,这里特意初始化为反方向m_state = CharacterState.ATTACK; //攻击状态m_direction = Orientation.WEST; //方向向左this.setTitle("明日非舟");this.setSize(800, 600);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setBackground(Color.white);this.setVisible(true);}
public static void main(String[] args) {// TODO Auto-generated method stubCharacter c = new Character();c.init();JPanel panel = new JPanel();//循环绘制while(true) {c.draw(c.getGraphics(), 50, 50, c);try {Thread.sleep(100);}catch(InterruptedException e) {e.printStackTrace();}}}
运行效果
总结
该Animation类只是提供一个动态图绘制的大致思想,具体运行还是要根据实际情况进行相应修改。
第一次写博客,还请多多包涵。
最后再次夸夸组长!组长的设计太厉害了。
整体代码
//Animation.java
package model;import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.util.Vector;import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;public class Animation {//动画图片集合public Vector<Image> m_images;//当前帧索引private int m_curFrameIndex;//尝试双缓冲的图片private Image buffer; private Graphics2D m_og;//Graphics2D设备可以进行一些图片处理//初始化public Animation() {m_images = new Vector<Image>();m_curFrameIndex = 0;}/*** 双缓冲绘制下一帧* @param g 当前面板的上下文设备* @param x 动画绘制的x坐标(图片的左上角点)* @param y 动画绘制的y坐标* @param panel 需要绘制的面板*/public void drawNextFrame(Graphics g,int x,int y,JFrame panel) {//得到需要绘制的图片Image img = this.getNextFrame();//得到面板和画图设备buffer = panel.createImage(panel.getWidth(),panel.getHeight());m_og = (Graphics2D) buffer.getGraphics();//双缓冲绘制图片if(img != null) {m_og.drawImage(img,x,y,panel);g.drawImage(buffer,0,0,null);}}//绘制反向下一帧,这里大致操作和上一个方法相同,只是多了一个把图片对称的操作。public void drawFilpFrame(Graphics g,int x,int y,JFrame panel) {//获取需要绘制的图片Image img = this.getNextFrame();//双缓冲绘制,获取当前需要绘制的面板buffer = panel.createImage(panel.getWidth(),panel.getHeight());m_og = (Graphics2D) buffer.getGraphics();//对图片进行对称变换!AffineTransform trans = new AffineTransform();//矩阵trans.scale(-1, 1);//根据y轴对称trans.translate(-(2*x+img.getWidth(null)), 0);//因为是整个画布移动所以要平移回去m_og.setTransform(trans);if(img != null) {m_og.drawImage(img,x,y,panel);g.drawImage(buffer,0,0,null);}}//获取下一帧public Image getNextFrame() {m_curFrameIndex = (m_curFrameIndex +1)%m_images.size();return (Image)m_images.elementAt(m_curFrameIndex);}/*** 加载图片集合* @param path 图片集的文件夹路径+‘/’* @param num 图片个数*/public void loadImages(String path,int num) {String index = "";for(int i=1;i<num;i++) {if(i<10) {index = "0"+i;}else {index = String.valueOf(i);}ImageIcon icon = new ImageIcon(path+index+".png");m_images.add(icon.getImage());}}
}
package test;import java.awt.Color;
import java.awt.Graphics;import javax.swing.JFrame;
import javax.swing.JPanel;public class Character extends JFrame {private static final long serialVersionUID = 1L;//状态static CharacterState m_state;//方向static Orientation m_direction;// 动画绘制工具:通用有 攻击、闲置、死亡……private Animation m_aniATK; private Animation m_aniIDLE;private Animation m_aniDIE;//……………………//初始化public void init() {//初始化图片集合(这里仅初始化攻击状态)m_aniATK = new Animation();m_aniATK.loadImages("Test/", 22); //载入攻击图片集合//初始化状态和方向,这里特意初始化为反方向m_state = CharacterState.ATTACK; //攻击状态m_direction = Orientation.WEST; //方向向左this.setTitle("明日非舟");this.setSize(800, 600);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setBackground(Color.white);this.setVisible(true);}public void draw(Graphics g,int x,int y,JFrame panel) {switch(m_state) {case ATTACK:if(this.m_direction == Orientation.EAST)m_aniATK.drawNextFrame(g, x, y, panel);elsem_aniATK.drawFilpFrame(g, x, y, panel);break;case IDLE:if(this.m_direction == Orientation.EAST)m_aniIDLE.drawNextFrame(g, x, y, panel);elsem_aniIDLE.drawFilpFrame(g, x, y, panel);break;case DIE:if(this.m_direction == Orientation.EAST)m_aniDIE.drawNextFrame(g, x, y, panel);elsem_aniDIE.drawFilpFrame(g, x, y, panel);break;}}public static void main(String[] args) {// TODO Auto-generated method stubCharacter c = new Character();c.init();JPanel panel = new JPanel();while(true) {c.draw(c.getGraphics(), 50, 50, c);try {Thread.sleep(100);}catch(InterruptedException e) {e.printStackTrace();}}}}
用Java实现一个游戏角色绘制的动画类相关推荐
- 【python】设计一个游戏角色类 属性:角色名、血量、魔法、状态 方法:释放技能 被伤害 要求:设计要合理
# 设计一个游戏角色类 # a. 属性:角色名.血量.魔法.状态 # b. 方法:释放技能 被伤害 # c. 要求:设计要合理 import time class Civillian:name=''b ...
- Java创建RPG游戏角色
◆题目名称 创建RPG游戏角色 ◆题目分析 该程序需要用到有关类与对象的知识点,所以不能使用C语言来编写代码,这里我选择Java语言.本题目要求的游戏角色应有以下属性:名字.性别.种族.职业.力量.敏 ...
- 用一个简单的创建游戏角色方案来理解类继承的运用以及浅淡protected权限修饰符的作用。
最近不知道怎得懒了许多,就是不想写总结. 想了想还是在这里说下protected的权限关系吧,怕大家在后面找不到 首先我们可能在学c++中都会听到老师说protected权限是介于public和pri ...
- 一个游戏角色秒杀10个白领月薪,制作过程原来是这样的
几乎每个热爱特效电影和游戏的人们在生活中都有一个好奇点,就是他在电影中看到某些东西并感到好奇时:"这些精美的场景,这些栩栩如生的怪物,他们到底是怎么做到的?" 从<指环王&g ...
- java制作一个游戏菜单_java连连看游戏菜单设计
本文实例为大家分享了java连连看游戏菜单的具体实现代码,供大家参考,具体内容如下 先写GUI. 首先初始化框架,菜单,按钮,需要把菜单和按钮都添加在框架中.注意添加的顺序,首先要设置菜单,再设置框架 ...
- PTA 用java编写 7-5 游戏角色选择
一款网游中包括4个种族:人类.精灵.兽人.暗精灵,每个种族包含三种角色:战士.法师.射手.玩家新建人物时需要选择种族和角色.请编写角色选择程序. 输入格式: 两个整数:游戏种族.角色的选项,以空格分隔 ...
- java画一个扇形_绘制并填充一个扇形
[c]代码库#include #include #include #include int main(void) { /* request auto detection */ int gdriver ...
- 暗黑风java战棋游戏_简约而不简单的类暗黑战棋游戏
评测:<符石守护者>--简约而不简单 一句话总结:国产战棋游戏精品 引入了大量暗黑因素的回合制游戏,在零零散散诸多设定下,竟然呈现出一种暗黑的游戏感,不得不令人叹服. <符石守护者& ...
- java编写一个动物类_Java编程 实现类的继承与多态 写一个动物类。成员变量为动物的种类,成员方法是动物叫声。...
感觉写得够详细了,如果不懂M我abstract class Animal { //动物的种类用变量n表示 String n; //动物的声音用变量s表示 String s; //在这里声明了一个抽象方 ...
最新文章
- Sqoop在导入MySQL数据时遇到Timestamp列为0000-00-00 00:00:00报错
- 【阿里云总监课第四期】时髦的云原生应用怎么写?
- A review of 3D/2D registration methods for image-guided interventions(2)
- 上古语言从入门到精通:COBOL 教程登上 GitHub 热榜
- HTML之CSS画三角形原理,纯CSS写三角形样式集合(原理解析)
- java去除字符串的空格,换行符,水平制表符,回车
- Flex调用WebService后的数据处理
- 图片服务 - thumbor过滤器
- java 根号_没见过的 Java 入门教程之三!例程使用中文标识符代码:各种变量
- Struts2标签库(四)之非表单标签
- java课程心得_Java课程感想
- keil5写c语言的步骤,keil5使用C51的详细步骤讲述
- 基于JAVA教师业绩考核和职称评审系统计算机毕业设计源码+数据库+lw文档+系统+部署
- FL studio 20简易入门教程 -- 第三篇 -- 菜单栏讲解(下)
- 基于Python+Django+mysql的实验室设备管理系统
- mysql中输出100内质数_SQL 打印 100 以内的质数
- [GPS]GPSGate x64下虚拟端口
- 破解win7开机密码
- PCL可视化,你想要一只五彩兔子吗
- CAN学习笔记---负载率计算