0450-Bomb-生成地图道具

环境

  • Time 2024-03-15
  • Zig 0.12.0-dev.3152+90c1a2c41
  • WSL-Ubuntu 22.04.3 LTS
  • raylib 5.0

前言

说明

参考资料:

  1. 《游戏开发:世嘉新人培训教材》
  2. 图片素材:https://www.ituring.com.cn/book/1742

目标

在上一节的基础上,再次生成地图上的道具。

map.zig

实现了地图上的道具的随机生成,重点在 generateItem 方法。

const std = @import("std");
const engine = @import("engine.zig");

var tileMap: engine.TileMap = undefined;

pub fn init() void {
    tileMap = engine.TileMap.init("map.png", 32);
}

pub fn deinit() void {
    tileMap.deinit();
}

const StageData = struct {
    enemy: usize,
    brickRate: usize,
    power: usize,
    bomb: usize,
};

const stageData = [_]StageData{
    .{ .enemy = 2, .brickRate = 90, .power = 4, .bomb = 6 },
    .{ .enemy = 3, .brickRate = 80, .power = 1, .bomb = 0 },
    .{ .enemy = 6, .brickRate = 30, .power = 0, .bomb = 1 },
};

// 定义地图的类型
pub const MapType = enum(u8) {
    space = 9,
    wall = 7,
    brick = 8,
    bomb = 2,
    power = 3,
};
const MapTypeSet = std.enums.EnumSet(MapType);

const width = 19;
const height = 15;
var data: [width * height]MapTypeSet = undefined;

fn toIndex(set: MapTypeSet) usize {
    return @intFromEnum(if (set.contains(.wall)) MapType.wall //
    // else if (set.contains(.brick)) MapType.brick //
    else if (set.contains(.bomb)) MapType.bomb //
    else if (set.contains(.power)) MapType.power //
    else MapType.space);
}

pub const WorldMap = struct {
    width: usize = width,
    height: usize = height,
    data: []MapTypeSet,

    pub fn init(_: std.mem.Allocator, _: usize) ?WorldMap {
        const map = WorldMap{ .data = &data };
        return map.generateMap(stageData[0]);
    }

    fn generateMap(self: WorldMap, info: StageData) WorldMap {
        var bricks: [data.len]usize = undefined;
        var brickNumber: usize = 0;
        for (0..self.height) |y| {
            for (0..self.width) |x| {
                self.data[x + y * width] = if (isFixWall(x, y))
                    MapTypeSet.initOne(.wall)
                else if (isFixSpace(x, y))
                    MapTypeSet.initOne(.space)
                else if (engine.random(100) < info.brickRate) label: {
                    bricks[brickNumber] = x << 16 | y;
                    brickNumber += 1;
                    break :label MapTypeSet.initOne(.brick);
                } else MapTypeSet.initOne(.space);
            }
        }
        generateItem(self, bricks[0..brickNumber], info);
        return self;
    }

    fn isFixWall(x: usize, y: usize) bool {
        if (x == 0 or y == 0) return true;
        if (x == width - 1 or y == height - 1) return true;
        if (x % 2 == 0 and y % 2 == 0) return true;
        return false;
    }

    fn isFixSpace(x: usize, y: usize) bool {
        return y + x < 4;
    }

    fn generateItem(self: WorldMap, bricks: []usize, info: StageData) void {
        for (0..info.bomb + info.power) |i| {
            const swapped = engine.randomX(i, bricks.len);
            const tmp = bricks[i];
            bricks[i] = bricks[swapped];
            bricks[swapped] = tmp;
            const x = bricks[i] >> 16 & 0xFFFF;
            const item: MapType = if (i < info.power) .power else .bomb;
            self.data[x + (bricks[i] & 0xFFFF) * self.width].insert(item);
        }
    }

    pub fn draw(self: WorldMap) void {
        for (0..self.height) |y| {
            for (0..self.width) |x| {
                const index = toIndex(data[x + y * self.width]);
                tileMap.drawI(index, x, y);
            }
        }
    }

    pub fn size(self: WorldMap) usize {
        return self.width * self.height;
    }

    pub fn deinit(_: WorldMap) void {
        // self.allocator.free(self.data);
    }
};

效果

bomb

总结

随机生成了地图上的道具。

附录

posted @ 2026-08-16 08:44  jiangbo4444  阅读(9)  评论(0)    收藏  举报