FXGL JAVA游戏引擎 教程 02.番外 组件优化

上文(02.组件)中我们一已经实现了移动组件,本文中将优化该组件。

刚才实现的速度组件大致有以下几个问题

  1. 速度并非具有由快到慢的变化,转变十分生硬。
  2. 速度大小并不能自定义
  3. 在同时触发多个键时可能出现不同的移动情况。

实现思路: 在触发按键时,加速速度,并且将状态标记为主动变化。在按键结束时,触发被动减速。

修改后的moveComponment为:

package com.dam.wonder.component;

import com.almasb.fxgl.core.math.Vec2;
import com.almasb.fxgl.entity.component.Component;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class MoveComponent extends Component {
    private double speedX = 0d;
    private double speedY = 0d;
    private double maxSpeed = 4d;
    private double aTime = 1d;
    private boolean speedXAdd;
    private boolean speedYAdd;
    @Override
    public void onUpdate(double tpf) {
//        log.info("当前状态下  x速度为=[{}], Y速度为=[{}]  x加速状态为=[{}] Y加速状态为 =[{}]",speedX,speedY,speedXAdd,speedYAdd);
            if (speedX != 0d) {
                    Vec2 dir = Vec2.fromAngle(entity.getRotation() - 360)
                            .mulLocal(speedX);
                    entity.translate(dir);
            }
            if (speedY != 0d) {
                    Vec2 dir = Vec2.fromAngle(entity.getRotation() - 90)
                            .mulLocal(speedY);
                    entity.translate(dir);
            }
            if (!speedXAdd) {
                slowDownSpeed(true);
            }
            if (!speedYAdd) {
                slowDownSpeed(false);
            }
    }

    public void up() {
        changeSpeed(true,false);
    }
    public void left() {
        changeSpeed(false,true);
    }
    public void right() {
       changeSpeed(true,true);
    }
    public void down(){
       changeSpeed(false,false);
    }
    public void stop() {
        speedX = 0d;
        speedY = 0d;
    }
    public void stopX() {
       speedXAdd = false;
    }
    public void stopY() {
       speedYAdd = false;
    }

    /**
     * 改变移动速度 主动改变
     * @param upOrDown
     * @param xOrY
     */
    private  void changeSpeed(boolean upOrDown,boolean xOrY) {
        if (xOrY) {
            speedXAdd = true;
            if (upOrDown) {
                if (speedX < maxSpeed) {
                    speedX = speedX + (float)maxSpeed/(10*aTime) + 0.01;
                }
            }else {
                if (speedX > -maxSpeed) {
                    speedX = speedX - (float)maxSpeed/(10f*aTime) - 0.01;
                }
            }
        }else {
            speedYAdd = true;
            if (upOrDown) {
                if (speedY < maxSpeed) {
                    speedY = speedY + (float)maxSpeed/(10f*aTime) + 0.01;
                }
            }else {
                if (speedY > -maxSpeed) {
                    speedY = speedY - (float)maxSpeed/(10f*aTime) - 0.01;
                }
            }
        }
    }

    /**
     * 速度减少 被动减速
     * @param xOrY
     */
    private void slowDownSpeed(boolean xOrY) {
        if (xOrY) {
            if (speedX > 0.5) {
                speedX = speedX - (float)speedX/10 -0.01;}
            else if (speedX< -0.5){
                speedX = speedX - (float)speedX/10 +0.01;
            }else {
                speedX = 0d;
            }
        }else {
            if (speedY > 0.5) {
                speedY = speedY - (float)speedY/10 -0.01;}
            else if (speedY< -0.5){
                speedY = speedY - (float)speedY/10 +0.01;
            }else {
                speedY = 0d;
            }
        }
    }



    public double getSpeedX() {
        return speedX;
    }

    public void setSpeedX(double speedX) {
        this.speedX = speedX;
    }

    public double getSpeedY() {
        return speedY;
    }

    public void setSpeedY(double speedY) {
        this.speedY = speedY;
    }

    public double getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(double maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public double getaTime() {
        return aTime;
    }

    public void setaTime(double aTime) {
        this.aTime = aTime;
    }
}

我增加了两个个全新的stop方法,用来标记该坐标轴上是否有按键在修改移动速度,如果没有则触发主动清空任务。并且给方法增加了加速时间atime这个属性,并增加了对应的全参数构造方法,熟悉lombok的同学可以很简单的理解这两个构造注解。

当然gameapp类也需要改变,会在文末突出。经过这个方法改造的组件将会有更流畅的操作体验,在飞机移动时的手感更佳。当然,除了自己书写相应的加减速规则之外,游戏引擎还提供了更加全功能的物理移动。还有物理碰撞检测等更加实用的组件。会在后文中一一指出。

FXGL 总目录

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FXGL 中,可以通过 `FXGL.getSceneService().pushScene(targetScene)` 方法来跳转到目标场景。为了方便起见,我们可以创建一个自定义的组件来实现场景跳转功能。 首先,创建一个名为 `SceneSwitchComponent` 的类,继承 `com.almasb.fxgl.entity.component.Component` 类,代码如下: ```java import com.almasb.fxgl.core.serialization.Bundle; import com.almasb.fxgl.entity.component.Component; public class SceneSwitchComponent extends Component { private String targetScene; public SceneSwitchComponent(String targetScene) { this.targetScene = targetScene; } @Override public void onUpdate(double tpf) { // 空实现,不需要实现 onUpdate 方法 } @Override public void onAdded() { // 点击实体时跳转到目标场景 entity.getViewComponent().addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { FXGL.getSceneService().pushScene(targetScene); }); } @Override public void onRemoved() { // 移除事件监听器 entity.getViewComponent().removeEventHandler(MouseEvent.MOUSE_CLICKED, event -> { FXGL.getSceneService().pushScene(targetScene); }); } @Override public void write(Bundle bundle) { bundle.put("targetScene", targetScene); } @Override public void read(Bundle bundle) { targetScene = bundle.get("targetScene"); } } ``` 这个组件包含一个 `targetScene` 字段,表示要跳转的目标场景名称。在 `onAdded()` 方法中,我们为实体的 `ViewComponent` 添加了一个鼠标点击事件监听器,当用户点击实体时,就会自动跳转到目标场景。`onRemoved()` 方法用于在移除组件时移除事件监听器。 接下来,在需要使用场景跳转功能的实体上添加 `SceneSwitchComponent` 组件即可。例如,我们可以创建一个名为 `Button` 的实体,代码如下: ```java import com.almasb.fxgl.entity.Entities; import com.almasb.fxgl.entity.Entity; import javafx.geometry.Pos; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.scene.text.Text; public class Button extends Entity { public Button(String text, String targetScene) { Text textNode = new Text(text); textNode.setFont(Font.font(24)); textNode.setFill(Color.WHITE); setViewFromNode(textNode); setAlignment(Pos.CENTER); addComponent(new SceneSwitchComponent(targetScene)); } } ``` 这个实体包含一个用于显示文本的 `Text` 节点,并且添加了一个 `SceneSwitchComponent` 组件。创建实体时需要传入两个参数,分别是文本内容和目标场景名称。 最后,在游戏场景中添加这个 `Button` 实体,代码如下: ```java import com.almasb.fxgl.app.scene.GameScene; import com.almasb.fxgl.entity.Entity; import com.almasb.fxgl.entity.Entities; public class MyGameScene extends GameScene { public MyGameScene() { Entity button = Entities.builder() .at(400, 300) .viewFromNode(new Button("跳转到场景2", "scene2")) .build(); addEntities(button); } } ``` 这里创建了一个名为 `MyGameScene` 的游戏场景,并且添加了一个 `Button` 实体。当用户点击这个实体时,就会自动跳转到名为 `scene2` 的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值