SpringBoot项目(二)--- 创建菜单和游戏界面

1.创建导航栏

因为每个界面的导航栏都是固定的,所以可以把导航栏写成一个组件。

如何单独写出一个组件并使用出来?

step1:在components文件夹下创建NavBar.vue文件

step2:在bootstrap上选择合适的样式复制下来

step3:在App.vue文件中导入NavBar.vue文件

<template>
  <NavBar />
  <router-view></router-view>
</template>

<script>
import NavBar from './components/NavBar.vue'
import "bootstrap/dist/css/bootstrap.min.css"  //要导入bootstrap的样式
import "bootstrap/dist/js/bootstrap"

export default {
  components: {
    NavBar
  }
}

</script>


<style>
body {
  background-image: url("@/assets/background.png");   /*图片地址*/
  background-size: cover;  /*百分百覆盖界面*/
}
</style>

2.调整导航栏的样式

3.创建其他的界面

pk界面、ranklist界面、record界面、404界面

如何实现根据url跳转到相应的界面呢? 使用vue的路由机制 在router文件夹下的index.js里面进行修改

import { createRouter, createWebHistory } from 'vue-router'

import PkIndexView from '../views/pk/PkIndexView'
import RankListIndexView from '../views/ranklist/RankListView'
import RecordIndexView from '../views/record/RecordIndex'
import UserBotIndexView from '../views/user/bot/UserBotIndex'
import NotFound from '../views/error/NotFound'

const routes = [
  //默认路由是pk界面
  {
    path:"/",
    name:"home",
    redirect:"/pk/"
  },
  {
    path:"/pk/",
    name:"pk_index",
    component:PkIndexView
  },
  {
    path:"/record/",
    name:"record_index",
    component:RecordIndexView
  },
  {
    path:"/ranklist/",
    name:"ranklist_index",
    component:RankListIndexView
  },
  {
    path:"/user/bot/",
    name:"user_bot_index",
    component:UserBotIndexView
  },
  {
    path:"/404/",
    name:"404",
    component:NotFound
  },
  {
    //匹配其他所有的非法的url
    path:"/:catchAll(.*)",
    redirect:"/404/"
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

实现点击界面上的按钮进行页面的跳转

方法1:修改href(每次都会刷新界面)

<a class="navbar-brand" href="/">King Of Bots</a>

方法2:(每次不会刷新界面)

将a标签改为router-link标签  name对应router下面的index.js里面的名称

<div class="container">
    <router-link class="navbar-brand" :to="{name:'home'}">King Of Bots</router-link>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
           <router-link class="nav-link" :to="{name:'pk_index'}">对战</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{name:'ranklist_index'}">对局列表</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{name:'record_index'}">排行榜</router-link>
        </li>
      </ul>
      <ul class="navbar-nav">
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            chenjiabin
          </a>
          <ul class="dropdown-menu">
            <li>
                <router-link class="dropdown-item" :to="{name:'user_bot_index'}">我的Bots</router-link>
            </li>
            <li><hr class="dropdown-divider"></li>
            <li><a class="dropdown-item" href="#">退出</a></li>
          </ul>
        </li>
      </ul>
    </div>

4.创建公共组件,放内容的(卡片) ContentField.vue

<template>
    <div class="container content-field">
        <div class="card">
            <div class="card-body">
                <slot>
                     
                </slot>
            </div>
        </div>
    </div>
</template>

<script>
//上面的slot标签等待被填充
</script>

<style scoped>
div.content-field {
    margin-top: 20px;
}
</style>

别的界面在导入

<template>
    <div>
        <ContentField>pk</ContentField>
    </div>
</template>

<script>

import ContentField from '../../components/ContentField.vue'

export default {
    components:{
        ContentField
    }
}
</script>

<style>
</style>

5.选中部分的高亮处理

使用vue的路由判断当前所在的界面,然后再从css上进行判断是否进行高亮处理

如何使用路由获取当前的界面?

<script>

import { useRoute } from 'vue-router';
import { computed } from 'vue';

export default {
  setup () {
    const route = useRoute();
    let route_name = computed( () => route.name);

    return {
      route_name
    }
  }
}
</script>

如何在css上进行判断?

<ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
           <router-link :class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link'" :to="{name:'pk_index'}">对战</router-link>
        </li>
        <li class="nav-item">
          <router-link :class="route_name == 'ranklist_index' ? 'nav-link active' : 'nav-link'" :to="{name:'ranklist_index'}">对局列表</router-link>
        </li>
        <li class="nav-item">
          <router-link :class="route_name == 'record_index' ? 'nav-link active' : 'nav-link'" :to="{name:'record_index'}">排行榜</router-link>
        </li>
      </ul>

其中 : 是v-bind 的缩写,用于绑定某个属性,到vue中去寻找这个值。.

6.画地图

每秒钟刷新60次,动态的计算,渲染帧(1s中60张图片)。

游戏当中需要动的每秒钟都要刷新60次,所以我们可以写一个基类AcGameObject.js来完成基本功能,别的功能来继承这个基类。

const AC_GAME_OBJECTS = [];

export class AcGameObject {
    constructor() {
        AC_GAME_OBJECTS.push(this);
        this.timedelta = 0;   //时间间隔
        this.has_called_start = false; 
    }


    start() {  //只执行一次,创建的时候执行

    }

    update() {  //每一帧执行一次,除了第一次之外

    }

    on_destory() {  //删除之前执行

    }
    
    destory() {
        this.on_destory();

        for(let i in AC_GAME_OBJECTS) {   //in是遍历的下标
            const obj = AC_GAME_OBJECTS[i];
            if(obj === this) {
                AC_GAME_OBJECTS.splice(i);
                break;
            }
        }
    }
}

let last_timestamp; //上一次执行的时刻
const step = timestamp => {
    for(let obj of AC_GAME_OBJECTS) {   //of遍历的是对象
        if(!obj.has_called_start) {
            obj.has_called_start = true;
            obj.start();
        }
        else {
            obj.timedelta = timestamp - last_timestamp;
            obj.update();
        }
    }
    requestAnimationFrame(step); //递归下去 每一帧都执行step
}

requestAnimationFrame(step);  //第一帧执行step

地图:

写一个GameMap组件,放地图

<template>
    <div  ref="parent" class="gamemap">
        <canvas ref="canvas"></canvas>
    </div>
</template>

<script>
//地图组件
import { GameMap } from '../assets/scripts/GameMap';
import { ref,onMounted } from 'vue';

export default {
    setup() {
        let parent = ref(null); //父元素  ref绑定div
        let canvas = ref(null);  //子元素  ref绑定canvas

        onMounted(() => {
            new GameMap(canvas.value.getContext("2d"),parent.value)
        });

        return {
            parent,
            canvas
        }
    }
}
</script>

<style scoped>
div.gamemap {
    width: 100%;
    height: 100%;
    
    display: flex;
    justify-content: center;
    align-items: center;
}
</style>

写一个地图类继承AcGameObject类

const AC_GAME_OBJECTS = [];

export class AcGameObject {
    constructor() {
        AC_GAME_OBJECTS.push(this);
        this.timedelta = 0;   //时间间隔
        this.has_called_start = false; 
    }


    start() {  //只执行一次,创建的时候执行

    }

    update() {  //每一帧执行一次,除了第一次之外

    }

    on_destory() {  //删除之前执行

    }

    destory() {
        this.on_destory();

        for(let i in AC_GAME_OBJECTS) {   //in是遍历的下标
            const obj = AC_GAME_OBJECTS[i];
            if(obj === this) {
                AC_GAME_OBJECTS.splice(i);
                break;
            }
        }
    }
}

let last_timestamp; //上一次执行的时刻
const step = timestamp => {
    for(let obj of AC_GAME_OBJECTS) {   //of遍历的是对象
        if(!obj.has_called_start) {
            obj.has_called_start = true;
            obj.start();
        }
        else {
            obj.timedelta = timestamp - last_timestamp;
            obj.update();
        }
    }
    requestAnimationFrame(step); //递归下去 每一帧都执行step
}

requestAnimationFrame(step);  //第一帧执行step

写一个墙类继承AcGameObject类

import { AcGameObject } from "./AcGameObject";

export class Wall extends AcGameObject {
    constructor(r,c,gamemap) {
        super();

        this.r = r;
        this.c = c;
        this.game = gamemap;
        this.color = "#B37226";
    }

    update() {
        this.render();
    }

    render() {
        const L = this.game.L;
        const ctx = this.game.ctx;

        ctx.fillStyle = this.color;
        ctx.fillRect(this.c * L,this.r * L,L,L);
    }
}

写一个地图类继承AcGameObject类

import { AcGameObject } from "./AcGameObject";
import { Wall } from './Wall.js';

export class GameMap extends AcGameObject  {
    constructor(ctx,parent) {
        super();

        this.ctx = ctx;
        this.parent = parent;
        this.L = 0; //每一个格子的边长

        this.rows = 13;
        this.cols = 13;

        this.inner_walls_count = 20;
        this.walls = [];
    }

    check_connectivity(g,sx,sy,tx,ty) {
        if(sx == tx && sy == ty) return true;
        g[sx][sy] = true;

        let dx = [-1,0,1,0],dy = [0,1,0,-1];
        for(let i = 0;i < 4;i ++) {
            let x = sx + dx[i],y = sy + dy[i];
            if(!g[x][y] && this.check_connectivity(g,x,y,tx,ty))
                return true;
        }
        return false;
    }
    create_walls() {
        //用一个bool类型的数组判断是否加障碍物  false代表还没加障碍物
        const g = [];
        for(let r = 0;r < this.rows;r ++) {
            g[r] = [];
            for(let c = 0;c < this.cols;c ++) {
                g[r][c] = false;
            }
        }

        //给四周加上障碍物
        for(let r = 0;r < this.rows;r ++) {
            g[r][0] = g[r][this.cols - 1] = true;
        }
        for(let c = 0;c < this.cols;c ++) {
            g[0][c] = g[this.rows - 1][c] = true;
        }

        //创建随机障碍物
        for(let i = 0;i < this.inner_walls_count / 2;i ++) {
            //随机出横纵坐标来  可能会重复,先弄1000次循环
            for(let j = 0;j < 1000;j ++) {
                let r = parseInt(Math.random() * this.rows);
                let c = parseInt(Math.random() * this.cols);
                if(g[r][c] || g[c][r]) continue;
                if(r == this.rows - 2 && c == 1 || r == 1 && c == this.cols - 2) continue;

                g[r][c] = g[c][r] = true;
                break;
            }
        }
        
        //复制一遍g数组
        const copy_g = JSON.parse(JSON.stringify(g));
        if(!this.check_connectivity(copy_g,this.rows - 2,1,1,this.cols - 2)) return false;

        for(let r = 0;r < this.rows;r ++) {
            for(let c = 0;c < this.cols;c ++) {
                if(g[r][c]) {
                    this.walls.push(new Wall(r,c,this));
                }
            }
        }
        return true;
    }
    start() {
        for(let i = 0;i < 1000;i ++) {
            if(this.create_walls())
                break;
        } 
    }

    update_size() {  //更新边长
        //求地图的最小的边长
        this.L = parseInt(Math.min(this.parent.clientWidth / this.cols,this.parent.clientHeight / this.rows));
        this.ctx.canvas.width = this.L * this.cols;
        this.ctx.canvas.height = this.L * this.rows;
    }
    update() {
        this.update_size();
        this.render(); //每一帧渲染一次
    }

     render() {
        const color_even = "#AAD751",color_odd = "#AAD254";
        for(let r = 0;r < this.rows;r ++) {
            for(let c = 0;c < this.cols;c ++) {
                if((r + c) % 2 == 0) {
                    this.ctx.fillStyle = color_even;
                } else {
                    this.ctx.fillStyle = color_odd;
                }
                this.ctx.fillRect(c * this.L,r * this.L,this.L,this.L);
            }
        }
        
     }
}

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IntelliJ IDEA 是一个强大的集成开发环境(IDE),特别适合于 Java 和 Spring Boot 项目的开发。下面是使用 IntelliJ IDEA 创建 Spring Boot 项目的步骤: 1. **打开 IntelliJ IDEA**: 打开你的 IntelliJ IDEA,如果还没有安装,请先下载并安装最新版本。 2. **新建项目**: 在欢迎界面或者菜单栏选择 "File" -> "New" -> "Project",然后选择 "Spring Initializr"。 3. **配置项目设置**: 在新窗口中,输入项目基本信息,例如: - **项目名称**: 选择一个描述性的名字。 - **Group Id**: 通常是 `com.yourcompany.yourproject` 格式。 - **Artifact Id**: 应该与 Group Id 匹配或稍作调整。 - **Language**: 选择 "Java". - **Spring Boot Version**: 选择你希望使用的 Spring Boot 版本,比如 2.x 或 3.x。 4. **添加依赖**: 在 "Dependencies" 部分,添加你需要的基础依赖,如 "Web"、"Data JPA" 或 "Thymeleaf"(如果你需要前端模板)。点击 "Add Dependency" 添加,或者直接在文本框中输入完整的依赖坐标。 5. **配置运行/打包**: 选择 "Run" -> "Edit Configurations",创建一个新的 "Application" 配置,指定主类(通常是 `Application`)和入口方法。 6. **导入到项目**: 在 "Initializr" 窗口中,点击 "Next: Configure Project Structure",然后点击 "Download and import",等待下载完成后,IntelliJ IDEA 将会自动导入项目。 7. **开始开发**: 导入后,你可以开始编写代码,使用IDEA的智能提示和代码补全功能。编辑完后,可以直接在 "Run" 或者 "Debug" 菜单项下启动项目

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值