JavaFX战旗类游戏开发 第三课 创建游戏角色

在上一节课程中,我们学习了在JavaFX中绘制游戏地图。这一节课,我们将会创建我们的游戏角色。

首先,同样的,我们创建一个简单的基类。

import javafx.scene.canvas.GraphicsContext;

/**
 * 游戏物体基类
 * @author Wing Mei
 */
public abstract class BaseObject {
	protected double x, y;
	protected double width,height;
	protected boolean isVisible;

	public abstract void draw(GraphicsContext gContext);
	public abstract void update();

	public void moveX(double x){
		setX(getX() + x);
	}

	public void moveY(double y){
		setY(getY() + y);
	}

	public void move(double x,double y){
		moveX(x);
		moveY(y);
	}

	public void setLocation(double x,double y){
		setX(x);
		setY(y);
	}

	public double getX() {
		return x;
	}

	public void setX(double x) {
		this.x = x;
	}

	public double getY() {
		return y;
	}

	public void setY(double y) {
		this.y = y;
	}

	public double getWidth() {
		return width;
	}

	public void setWidth(double width) {
		this.width = width;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}

    public boolean isCollisionWith(double x,double y){
        if(x > getX() && y > getY() && x < getX() + getWidth() && y < getY() + getHeight()){
            return true;
        }
        return false;
    }
	public boolean isVisible() {
		return isVisible;
	}
	public void setVisible(boolean isVisible) {
		this.isVisible = isVisible;
	}
}

注意了,通常JavaFX中的类的变量,最好采用JavaFX的Property(javafx.bean.property),在后期很多处理上通过绑定机制会很方便,在我本人的JavaFX游戏开发库中都是采用的这个机制。不过在这里,由于赶工,并未使用。只是在此说明一下。

基类中,只是基本的坐标,大小的属性和基本的碰撞函数。

下面看看我们的角色类:

import java.util.List;
import java.util.Random;

import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;

public class BasePlayer extends BaseObject {
	//角色分组 玩家 敌人 中立(暂未用到)
	public enum Group {
		Player, Enemy, Normal
	}
	private String name = "默认";
	private int lv = 1;
	private int attack = 3;
	private int defense = 1;
	private int hp = 6;
	private int hp_max = 6;
	private int exp = 0;
	private int gold = 1;
	private int move = 4;
	private Random random = new Random();
	private Image image;
	private Group group = Group.Player;
        //是否被选择
	private boolean isChoose = false;
	//是否正在等待攻击(已显示攻击范围)
	private boolean isWaitToAttack = false;
	//是否正在等待移动(已显示移动范围)
	private boolean isWaitToMove = false;
	//是否能够行动
	private boolean isCanAction = true;
	//是否能够移动
	private boolean isCanMove = true;
	//是否能够攻击
	private boolean isCanAttack = true;
        //下面是被攻击后的属性(本想做成闪烁,后来图简单没搞,名称未改)
	private int flashCount = 10;
	private int startCount = 0;
	private boolean isFlash = false;

	/**
	 * 等级提升
	 */
	public void levelUp() {
		attack += random.nextInt(3);
		defense += random.nextInt(2);
		hp += random.nextInt(3);
		lv++;
	}

	/**
	 * 获取经验证
	 * @param ex 经验值
	 */
	public void getExp(int ex){
		exp += ex;
		if(exp >= 100){
			levelUp();
			exp = 0;
		}
	}

	/**
	 * 攻击
	 * @param player 被攻击的角色
	 */
	public void attack(BasePlayer player) {
		player.hp -= Math.max(0, attack - player.defense);
	}

	public void draw(GraphicsContext gc) {
		gc.save();
		if (image != null) {
			if (isCanAction) {  //如果行动未结束
				if (isFlash) {  //如果被攻击,绘制红色填充矩形,并等待计数结束
					if (startCount < flashCount) {
						gc.setGlobalAlpha(0.3f);
						gc.setFill(Color.RED);
						gc.fillRect(getX(), getY(), width, height);
						startCount ++ ;
					} else {
						startCount = 0;
						isFlash = false;
					}
				}
				gc.setGlobalAlpha(1.0f);
				gc.drawImage(image, x, y);
			} else { //行动结束 透明度变为0.5
				gc.setGlobalAlpha(0.5f);
				gc.drawImage(image, x, y);
			}
			gc.setGlobalAlpha(1.5f);
			if (isChoose) { // 当被选择时,显示边框
				gc.strokeRect(x, y, 32, 32);
			}
		}
		gc.restore();
	}

	/*
	 * 被攻击 效果
	 */
	public void flash() {
		isFlash = true;
		startCount = 0;
	}

	/**
	 * 是否附近有Players里的角色
	 *
	 * @param players
	 *            角色集合
	 * @return 是否附近有Players里的角色
	 */
	public boolean isHasNearBP(List<BasePlayer> players) {
		int mx = (int) (getX() / width);
		int my = (int) (getY() / height);
		for (BasePlayer bp : players) {
			int x = (int) (bp.getX() / width);
			int y = (int) (bp.getY() / height);
			if ((x == mx && y == my + 1) || (x == mx - 1 && y == my) || (x == mx + 1 && y == my)
					|| (x == mx && y == my - 1)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 寻找离自己最近的角色
	 *
	 * @param players
	 *            角色集合
	 * @return 最近的角色
	 */
	public BasePlayer getNearestBP(List<BasePlayer> players) {
		BasePlayer basePlayer = players.get(0);
		for (int i = 0; i < players.size(); i++) {
			BasePlayer player = players.get(i);
			if (Math.abs(getX() - basePlayer.getX()) + Math.abs(getY() - basePlayer.getY()) > Math.abs(getX()
					- player.getX())
					+ Math.abs(getY() - player.getY())) {
				basePlayer = player;
			}
		}
		return basePlayer;
	}

	@Override
	public void update() {

	}

	/**
	 * 重置所有状态
	 */
	public void reset() {
		isChoose = false;
		isWaitToAttack = false;
		isWaitToMove = false;
		isCanAction = true;
		isCanMove = true;
		isCanAttack = true;
	}

	/**
	 *  判断是否与某个点碰撞
	 */
	public boolean isCollisionWith(double x, double y) {
		if (x > getX() && y > getY() && x < getX() + getWidth() && y < getY() + getHeight()) {
			return true;
		}
		return false;
	}

	public int getLv() {
		return lv;
	}

	public void setLv(int lv) {
		this.lv = lv;
	}

	public int getAttack() {
		return attack;
	}

	public void setAttack(int attack) {
		this.attack = attack;
	}

	public int getDefense() {
		return defense;
	}

	public void setDefense(int defense) {
		this.defense = defense;
	}

	public int getHp() {
		return hp;
	}

	public void setHp(int hp) {
		this.hp = hp;
	}

	public int getExp() {
		return exp;
	}

	public void setExp(int exp) {
		this.exp = exp;
	}

	public int getGold() {
		return gold;
	}

	public void setGold(int gold) {
		this.gold = gold;
	}

	public Image getImage() {
		return image;
	}

	public void setImage(Image image) {
		this.image = image;
		setWidth(image.getWidth());
		setHeight(image.getHeight());
	}

	public boolean isChoose() {
		return isChoose;
	}

	public void setChoose(boolean isChoose) {
		this.isChoose = isChoose;
	}

	public int getMove() {
		return move;
	}

	public void setMove(int move) {
		this.move = move;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isWaitToAttack() {
		return isWaitToAttack;
	}

	public void setWaitToAttack(boolean isWaitToAttack) {
		this.isWaitToAttack = isWaitToAttack;
	}

	public boolean isWaitToMove() {
		return isWaitToMove;
	}

	public void setWaitToMove(boolean isWaitToMove) {
		this.isWaitToMove = isWaitToMove;
	}

	public Group getGroup() {
		return group;
	}

	public void setGroup(Group group) {
		this.group = group;
	}

	public boolean isCanAction() {
		return isCanAction;
	}

	public void setCanAction(boolean isCanAction) {
		this.isCanAction = isCanAction;
	}

	public boolean isCanMove() {
		return isCanMove;
	}

	public void setCanMove(boolean isCanMove) {
		this.isCanMove = isCanMove;
	}

	public boolean isCanAttack() {
		return isCanAttack;
	}

	public void setCanAttack(boolean isCanAttack) {
		this.isCanAttack = isCanAttack;
	}

	public boolean isFlash() {
		return isFlash;
	}

	public void setFlash(boolean isFlash) {
		this.isFlash = isFlash;
	}

	public int getHpMax() {
		return hp_max;
	}

	public void setHpMax(int hp_max) {
		this.hp_max = hp_max;
	}
}

在我的角色类中,定义了基本游戏角色的基本属性,名称,等级,攻击力,防御力,HP,经验值,金钱,移动力等。有一些暂时没有用到,不过没关系,都有注释。

另外定义几个方法,等级上升,获取经验值,攻击敌人,判断周边四个是否有角色(用于攻击判断),获取最近的角色(用于敌方移动目标确定)。

下面开始添加我们的角色了:

在Canvas的定义里增加我方角色和敌方角色的列表。

	// 我方角色
	private List<BasePlayer> players = new ArrayList<>();
	// 敌方角色
	private List<BasePlayer> enemys = new ArrayList<BasePlayer>();

初始化我方角色和敌人角色:

/**
	 * 初始化我方角色
	 */
	private void initPlayers() {
		Image player1Image = new Image(getClass().getResourceAsStream("player1.png"));
		BasePlayer player1 = new BasePlayer();
		player1.setName("茉妍");
		player1.setImage(player1Image);
		player1.setLocation(10 * tileWidth, 8 * tileHeight);

		Image player2Image = new Image(getClass().getResourceAsStream("player2.png"));
		BasePlayer player2 = new BasePlayer();
		player2.setName("张达");
		player2.setImage(player2Image);
		player2.setLocation(12 * tileWidth, 8 * tileHeight);

		Image player3Image = new Image(getClass().getResourceAsStream("player3.png"));
		BasePlayer player3 = new BasePlayer();
		player3.setName("燕鱈");
		player3.setImage(player3Image);
		player3.setLocation(8 * tileWidth, 8 * tileHeight);

		players.add(player1);
		players.add(player2);
		players.add(player3);
	}

	/**
	 * 初始化敌方角色
	 */
	private void initEnemy() {
		Image orc = new Image(getClass().getResourceAsStream("enemy1.png"));
		int[][] locations = { { 3, 3 }, { 3, 5 }, { 5, 3 } };
		for (int i = 0; i < 3; i++) {
			BasePlayer enemy = new BasePlayer();
			enemy.setImage(orc);
			enemy.setName("信(克隆)");
			enemy.setAttack(3);
			enemy.setDefense(1);
			enemy.setHp(5);
			enemy.setHpMax(5);
			enemy.setGroup(Group.Enemy);
			enemy.setMove(3);
			enemy.setExp(50);
			enemy.setLocation(locations[i][0] * tileWidth, locations[i][1] * tileHeight);
			enemys.add(enemy);
		}
	}

注意这两个初始化方法要放入构造函数。另外,角色的Group分类一定要明确。

还有图片资源放入Src下和java文件的同级目录中。

接着开始绘制:

	/**
	 * 绘制角色
	 */
	public void drawPlayer() {
		for (BasePlayer player : players) {
			player.draw(gContext);
		}
		for (BasePlayer enemy : enemys) {
			enemy.draw(gContext);
		}
	}

drawPlayer方法同样的在draw方法中调用。

这样以来,我们的角色和敌方角色也都创建完成了。

下面是效果图:

这样,我们的角色就创建完成了。

这一节课也到此结束了,下一节课,我们将会创建我们的行动菜单,属性菜单等。

本文章为个人原创,版权所有,转载请注明出处:http://blog.csdn.net/ml3947。另外我的个人博客:http://www.wjfxgame.com.

JavaFX战旗类游戏开发 第三课 创建游戏角色

时间: 2024-10-10 14:42:56

JavaFX战旗类游戏开发 第三课 创建游戏角色的相关文章

JavaFX战旗类游戏开发 第四课 属性框和菜单的创建

上一课中,我们创建了游戏角色.这节课中,我们将会创建菜单,以便后面使用. 由于只是Demo,我创建的是最简单的形式,如下图所示: 基于游戏开发中的UI控件通常需要有事件(比如图中的移动,攻击,待机,是有事件处理的),我们应该首先创建自己的文字控件. 文字控件代码如下: import com.sun.javafx.tk.FontMetrics; import com.sun.javafx.tk.Toolkit; import javafx.scene.canvas.GraphicsContext;

JavaFX战旗类游戏开发 第二课 游戏地图绘制

在上一节课中,我们对即将要完成的战旗Demo有了一个大概的了解,本节课当中,我们将会学习绘制游戏地图. 自从在JavaFX 2.2中增加了Canvas相关的功能,我们就可以使用Canvas来实现游戏绘制了. 游戏地图绘制主要用到GraphicsContext.drawImage方法. drawImage(Image image,double sx,double sy,double sw,double sh,double dx,double dy,double dw,double dh); 其中i

JavaFX战旗游戏开发 第七课 回合逻辑(完)

上一节课中,我们讲述了SLG中获取移动范围的算法(获取攻击范围也是同理),相对如自动寻径来说,简单不少.由于个人时间问题,这一节课将会把内容讲完,将这个系列完结,并给出示例下载地址. 项目下载地址:JavaFX战旗类游戏开发示例 注意:该项目为e(fx)clipse项目 在战旗游戏开发中,最基本的回合逻辑就是敌方回合和我方回合.当然,在如今的SLG游戏中,往往是根据我方角色和敌方角色的某些数值计算(例如速度之类的),来排列角色操控的列表,而且某些技能还能中断某个角色的操作,将他往操作列表的后面移

游戏开发(三)——WIN32 黑白棋(三)——游戏画面的现实

整个游戏分3部分介绍. 1.棋局的现实 2.AI的现实 3.游戏画面的现实 提供一下完整项目下载 这是第三部分:画面的显示 这部分其实就比较简单的,说白了就是api的堆砌. 主要了解下windows的消息机制,以及怎么画图 主要是分别封装了下对棋盘,棋子,以及当前轮到谁,当前比分是多少,就是游戏画面上不同的部分的绘制. void DrawReversiBoard(); void DrawReversiPieces(EnumReversiPiecesType type, int row_y, in

游戏开发(三)——WIN32 黑白棋(二)——AI

今天是第二部分:玩家和AI 玩家主要是实现悔棋的功能 AI主要是搜索.最大最小算法,枝剪算法 1.每一步落子的步骤,为了可以悔棋 typedef struct ReversiStep {     ReversiBitBoard m_LastMap;     ReversiStep& operator= (const ReversiStep& temp)     {         m_LastMap = temp.m_LastMap;         return *this;     }

游戏开发(三)——WIN32 黑白棋(一)——棋局逻辑的设计

今天以黑白棋为例,开始给一个win32的小游戏设计, 这里打算分3部分介绍 1.棋盘,棋局的现实 2.玩家.AI的现实(且听下回分解) 3.游戏画面的现实(且听下下回分解) 其中第一部分为黑白棋游戏的主要逻辑: 1.棋盘,以及棋盘上的棋子的存储形式.这里用到了位图. 2.是否可以落子的判断(黑白棋是只有你落子的位置,在横竖斜八个方向中任意一个方向,能吃掉对方的子,你才可以落在该位置,八个方向都吃不掉对方子的位置是不能下的),以及吃子的逻辑(吃子的逻辑同样是八个方向,两个己方棋子之间夹住的对方棋子

Unity 游戏开发技巧集锦之创建部分光滑部分粗糙的材质

Unity 游戏开发技巧集锦之创建部分光滑部分粗糙的材质 创建部分光滑部分粗糙的材质 生活中,有类物体的表面既有光滑的部分,又有粗糙的部分,例如丽江的石板路,如图3-17所示,石板的表面本来是粗糙的,但是在石板上面走的人多了,石板的一部分就变得光滑了.有时,游戏为了显得更加逼真,就需要模拟这样一种材质. 图3-17  兼具光滑和粗糙表面的丽江石板路 要制作部分光滑部分粗糙的材质,需要用到两种资源:拥有镜面着色器的材质和模拟了现实状况的纹理. Unity中创建并配置材质 在Project视图里,创

最大的幻术-游戏开发-到底是先学游戏引擎还是先学游戏编程

学习游戏的目的 我们学习游戏制作,游戏开发,游戏编程,游戏XX,我们的目的只有一个,打造一个非常牛逼,非常屌,非常让人开心的虚拟体验.我们用自己的学识让玩家在虚拟世界征战,生活,一步一步的让玩家幸福!那么我们的目的只有一个,让玩家知道自己的幸福在哪里,并且学会追求自己的幸福.当然,每个人对幸福的定义不一样.那么,我们只好让玩家来体验我们所来表达的最通俗的,最普遍的幸福体验,然后慢慢引导玩家去寻找自己的幸福体验.可能,在最后玩家都会离开游戏,离开虚拟世界,(对,这是真的,玩家需要一步一步达到定点,

Unity 游戏开发技巧集锦之创建透明的材质

Unity 游戏开发技巧集锦之创建透明的材质 Unity创建透明的材质 生活中不乏透明或者半透明的事物.例如,擦的十分干净的玻璃,看起来就是透明的:一些塑料卡片,看起来就是半透明的,如图3-23所示.在Unity中,可以创建模拟了透明效果的材质,这也是本节主要讲解的内容. 图3-23  半透明的卡片 Unity创建并配置材质 在Project视图里,创建一个材质,并命名为TransMaterial,选中它然后在Inspector视图里修改Shader属性为Transparent/Diffuse,