三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

0445-Bomb-实现进入下一关

0445-Bomb-实现进入下一关

环境

  • Time 2024-03-14
  • 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

目标

如果游戏关卡完成,显示提示信息,等待两秒后跳转下一关。

play.zig

加入了进入下一关的调试代码。

const std = @import("std");
const engine = @import("engine.zig");
const map = @import("map.zig");pub fn init(allocator: std.mem.Allocator, level: usize, box: engine.Texture) ?Play {const m = map.Map.init(allocator, level) catch |err| {std.log.err("init stage error: {}", .{err});return null;} orelse return null;return .{ .map = m, .box = box };
}pub const Play = struct {map: map.Map,box: engine.Texture,pub fn update(_: *Play) ?@import("popup.zig").PopupType {if (engine.isPressed(engine.Key.x)) return .over;if (engine.isPressed(engine.Key.c)) return .clear;return null;}pub fn draw(self: Play) void {for (0..self.map.height) |y| {for (0..self.map.width) |x| {const item = self.map.data[y * self.map.width + x];if (item != map.MapItem.WALL) {self.drawCell(x, y, if (item.hasGoal()) .GOAL else .SPACE);}if (item != .SPACE) self.drawCell(x, y, item);}}}fn drawCell(play: Play, x: usize, y: usize, item: map.MapItem) void {var source = engine.Rectangle{ .width = 32, .height = 32 };source.x = item.toImageIndex() * source.width;const position = .{ .x = x * source.width, .y = y * source.height };play.box.drawRectangle(source, position);}pub fn deinit(self: Play) void {self.map.deinit();}
};

popup.zig

抽取了 TimePopup 来实现定时显示弹出消息的功能,clear 和 over 使用了这个。

const std = @import("std");
const engine = @import("engine.zig");
const map = @import("map.zig");pub const MenuType = enum { quit, title, select, reset, next };
pub const PopupType = enum { loading, menu, clear, over };pub const Popup = union(PopupType) {loading: Loading,menu: Menu,clear: TimePopup,over: TimePopup,pub fn update(self: *Popup) ?MenuType {return switch (self.*) {inline else => |*case| case.update(),};}pub fn draw(self: Popup) void {switch (self) {inline else => |sequence| sequence.draw(),}}pub fn deinit(self: Popup) void {switch (self) {inline else => |sequence| sequence.deinit(),}}
};pub fn init() Popup {return .{ .loading = Loading.init() };
}pub fn initWithType(popupType: PopupType) Popup {return switch (popupType) {.clear => .{ .clear = TimePopup.init("clear.png", .next) },.menu => .{ .menu = Menu.init() },.loading => .{ .loading = Loading.init() },.over => .{ .over = TimePopup.init("over.png", .title) },};
}const TimePopup = struct {texture: engine.Texture,time: usize,target: MenuType,fn init(name: []const u8, target: MenuType) TimePopup {return TimePopup{.texture = engine.Texture.init(name),.time = engine.time(),.target = target,};}fn update(self: TimePopup) ?MenuType {return if (engine.time() - self.time > 2000) self.target else null;}fn draw(self: TimePopup) void {self.texture.draw();}fn deinit(self: TimePopup) void {self.texture.deinit();}
};const Loading = struct {texture: engine.Texture,time: usize,fn init() Loading {return Loading{.texture = engine.Texture.init("loading.dds"),.time = engine.time(),};}fn update(self: Loading) ?MenuType {return if (engine.time() - self.time > 1000) return .quit else null;}fn draw(self: Loading) void {self.texture.draw();}fn deinit(self: Loading) void {self.texture.deinit();}
};const Menu = struct {texture: engine.Texture,fn init() Menu {return Menu{ .texture = engine.Texture.init("menu.dds") };}fn update(_: Menu) ?MenuType {const char = engine.getPressed();return switch (char) {'1' => .reset,'2' => .select,'3' => .title,'4' => .quit,else => null,};}fn draw(self: Menu) void {self.texture.draw();}fn deinit(self: Menu) void {self.texture.deinit();}
};

stage.zig

抽取了新建 Popup 的功能到 popup.zig 模块。

const std = @import("std");
const popup = @import("popup.zig");
const play = @import("play.zig");const Texture = @import("engine.zig").Texture;
pub const SequenceType = enum { title, select, stage };
pub const SequenceData = union(SequenceType) {title: void,select: void,stage: usize,
};pub fn init(allocator: std.mem.Allocator, level: usize, box: Texture) ?Stage {const current = play.init(allocator, level, box) orelse return null;return Stage{ .level = level, .current = current, .popup = popup.init() };
}pub const Stage = struct {level: usize,current: play.Play,popup: ?popup.Popup = null,pub fn update(self: *Stage) ?SequenceData {if (self.popup) |*option| {const menu = option.update() orelse return null;defer option.deinit();switch (menu) {.title => return .title,.select => return .select,.reset => return .{ .stage = self.level },.next => return .{ .stage = self.level + 1 },.quit => self.popup = null,}}const popupType = self.current.update() orelse return null;self.popup = popup.initWithType(popupType);return null;}pub fn draw(self: Stage) void {self.current.draw();if (self.popup) |option| option.draw();}pub fn deinit(self: Stage) void {if (self.popup) |option| option.deinit();self.current.deinit();}
};

效果

bomb

总结

实现炸弹人的下一关功能。

附录

← 返回列表