feat: 新增AI创作中心场景,支持改写/续写/创作

This commit is contained in:
2026-03-03 17:06:08 +08:00
parent cc0e39cccc
commit 699362cc7d
6 changed files with 1290 additions and 1 deletions

View File

@@ -0,0 +1,794 @@
/**
* AI创作中心场景
*/
import BaseScene from './BaseScene';
export default class AICreateScene extends BaseScene {
constructor(main, params) {
super(main, params);
this.currentTab = 0; // 0:改写 1:续写 2:创作
this.tabs = ['AI改写', 'AI续写', 'AI创作'];
// 滚动
this.scrollY = 0;
this.maxScrollY = 0;
this.isDragging = false;
this.lastTouchY = 0;
this.hasMoved = false;
// 用户数据
this.recentStories = [];
this.aiHistory = [];
this.quota = { daily: 3, used: 0, purchased: 0 };
// 创作表单
this.createForm = {
genre: '',
keywords: '',
protagonist: '',
conflict: ''
};
// 选中的故事(用于改写/续写)
this.selectedStory = null;
// 快捷标签
this.rewriteTags = ['主角逆袭', '甜蜜HE', '虐心BE', '反转剧情', '意外重逢', '身份揭秘'];
this.continueTags = ['增加悬念', '感情升温', '冲突加剧', '真相大白', '误会解除'];
this.genreTags = ['都市言情', '古风宫廷', '悬疑推理', '校园青春', '修仙玄幻', '职场商战'];
}
async init() {
await this.loadData();
}
async loadData() {
try {
// 加载最近游玩的故事
this.recentStories = await this.main.userManager.getRecentPlayed() || [];
// 加载AI创作历史
this.aiHistory = await this.main.userManager.getAIHistory() || [];
// 加载配额
const quotaData = await this.main.userManager.getAIQuota();
if (quotaData) this.quota = quotaData;
} catch (e) {
console.error('加载数据失败:', e);
}
this.calculateMaxScroll();
}
calculateMaxScroll() {
let contentHeight = 400;
if (this.currentTab === 0 || this.currentTab === 1) {
contentHeight = 300 + this.recentStories.length * 80;
} else {
contentHeight = 600;
}
this.maxScrollY = Math.max(0, contentHeight - this.screenHeight + 200);
}
update() {}
render(ctx) {
this.renderBackground(ctx);
this.renderHeader(ctx);
this.renderQuotaBar(ctx);
this.renderTabs(ctx);
this.renderContent(ctx);
}
renderBackground(ctx) {
const gradient = ctx.createLinearGradient(0, 0, 0, this.screenHeight);
gradient.addColorStop(0, '#0f0c29');
gradient.addColorStop(0.5, '#302b63');
gradient.addColorStop(1, '#24243e');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, this.screenWidth, this.screenHeight);
// 装饰光效
const glow = ctx.createRadialGradient(this.screenWidth / 2, 150, 0, this.screenWidth / 2, 150, 200);
glow.addColorStop(0, 'rgba(168, 85, 247, 0.15)');
glow.addColorStop(1, 'transparent');
ctx.fillStyle = glow;
ctx.fillRect(0, 0, this.screenWidth, 300);
}
renderHeader(ctx) {
// 顶部遮罩
const headerGradient = ctx.createLinearGradient(0, 0, 0, 80);
headerGradient.addColorStop(0, 'rgba(15,12,41,1)');
headerGradient.addColorStop(1, 'rgba(15,12,41,0)');
ctx.fillStyle = headerGradient;
ctx.fillRect(0, 0, this.screenWidth, 80);
// 返回按钮
ctx.fillStyle = '#ffffff';
ctx.font = '16px sans-serif';
ctx.textAlign = 'left';
ctx.fillText(' 返回', 15, 40);
// 标题
ctx.textAlign = 'center';
ctx.font = 'bold 18px sans-serif';
const titleGradient = ctx.createLinearGradient(this.screenWidth / 2 - 50, 0, this.screenWidth / 2 + 50, 0);
titleGradient.addColorStop(0, '#a855f7');
titleGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = titleGradient;
ctx.fillText('✨ AI创作中心', this.screenWidth / 2, 40);
}
renderQuotaBar(ctx) {
const barY = 60;
const remaining = this.quota.daily - this.quota.used + this.quota.purchased;
// 配额背景
ctx.fillStyle = 'rgba(255,255,255,0.08)';
this.roundRect(ctx, 15, barY, this.screenWidth - 30, 36, 18);
ctx.fill();
// 配额文字
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.font = '12px sans-serif';
ctx.textAlign = 'left';
ctx.fillText(`今日剩余: ${remaining}`, 30, barY + 23);
// 充值按钮
const btnWidth = 70;
const btnX = this.screenWidth - 30 - btnWidth;
const btnGradient = ctx.createLinearGradient(btnX, barY + 5, btnX + btnWidth, barY + 5);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, btnX, barY + 5, btnWidth, 26, 13);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 11px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('获取更多', btnX + btnWidth / 2, barY + 22);
this.quotaBtnRect = { x: btnX, y: barY + 5, width: btnWidth, height: 26 };
}
renderTabs(ctx) {
const tabY = 110;
const tabWidth = (this.screenWidth - 40) / 3;
const padding = 15;
this.tabRects = [];
this.tabs.forEach((tab, index) => {
const x = padding + index * (tabWidth + 5);
const isActive = index === this.currentTab;
if (isActive) {
const gradient = ctx.createLinearGradient(x, tabY, x + tabWidth, tabY);
gradient.addColorStop(0, '#a855f7');
gradient.addColorStop(1, '#ec4899');
ctx.fillStyle = gradient;
} else {
ctx.fillStyle = 'rgba(255,255,255,0.1)';
}
this.roundRect(ctx, x, tabY, tabWidth, 36, 18);
ctx.fill();
ctx.fillStyle = isActive ? '#ffffff' : 'rgba(255,255,255,0.6)';
ctx.font = isActive ? 'bold 13px sans-serif' : '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(tab, x + tabWidth / 2, tabY + 23);
this.tabRects.push({ x, y: tabY, width: tabWidth, height: 36, index });
});
}
renderContent(ctx) {
const contentY = 160;
ctx.save();
ctx.beginPath();
ctx.rect(0, contentY, this.screenWidth, this.screenHeight - contentY);
ctx.clip();
switch (this.currentTab) {
case 0:
this.renderRewriteTab(ctx, contentY);
break;
case 1:
this.renderContinueTab(ctx, contentY);
break;
case 2:
this.renderCreateTab(ctx, contentY);
break;
}
ctx.restore();
}
renderRewriteTab(ctx, startY) {
const y = startY - this.scrollY;
const padding = 15;
// 说明文字
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('选择一个已玩过的故事AI帮你改写结局', this.screenWidth / 2, y + 25);
// 快捷标签
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.font = '12px sans-serif';
ctx.textAlign = 'left';
ctx.fillText('热门改写方向:', padding, y + 60);
this.renderTags(ctx, this.rewriteTags, padding, y + 75, 'rewrite');
// 选择故事
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.font = '13px sans-serif';
ctx.fillText('选择要改写的故事:', padding, y + 145);
this.renderStoryList(ctx, y + 160, 'rewrite');
}
renderContinueTab(ctx, startY) {
const y = startY - this.scrollY;
const padding = 15;
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('选择一个进行中的故事AI帮你续写剧情', this.screenWidth / 2, y + 25);
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.font = '12px sans-serif';
ctx.textAlign = 'left';
ctx.fillText('续写方向:', padding, y + 60);
this.renderTags(ctx, this.continueTags, padding, y + 75, 'continue');
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.font = '13px sans-serif';
ctx.fillText('选择要续写的故事:', padding, y + 145);
this.renderStoryList(ctx, y + 160, 'continue');
}
renderCreateTab(ctx, startY) {
const y = startY - this.scrollY;
const padding = 15;
const inputWidth = this.screenWidth - padding * 2;
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('输入关键词AI为你创作全新故事', this.screenWidth / 2, y + 25);
// 题材选择
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'left';
ctx.fillText('选择题材:', padding, y + 60);
this.renderTags(ctx, this.genreTags, padding, y + 75, 'genre');
// 关键词输入
ctx.fillText('故事关键词:', padding, y + 145);
this.renderInputBox(ctx, padding, y + 160, inputWidth, 45, this.createForm.keywords || '例如:霸总、契约婚姻、追妻火葬场', 'keywords');
// 主角设定
ctx.fillText('主角设定:', padding, y + 225);
this.renderInputBox(ctx, padding, y + 240, inputWidth, 45, this.createForm.protagonist || '例如:独立女性设计师', 'protagonist');
// 核心冲突
ctx.fillText('核心冲突:', padding, y + 305);
this.renderInputBox(ctx, padding, y + 320, inputWidth, 45, this.createForm.conflict || '例如:假结婚变真爱', 'conflict');
// 开始创作按钮
const btnY = y + 400;
const btnGradient = ctx.createLinearGradient(padding, btnY, this.screenWidth - padding, btnY);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, padding, btnY, inputWidth, 50, 25);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 16px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('✨ 开始AI创作', this.screenWidth / 2, btnY + 32);
this.createBtnRect = { x: padding, y: btnY + this.scrollY, width: inputWidth, height: 50 };
}
renderTags(ctx, tags, startX, startY, type) {
const tagHeight = 30;
const tagGap = 8;
let currentX = startX;
let currentY = startY;
if (!this.tagRects) this.tagRects = {};
this.tagRects[type] = [];
tags.forEach((tag, index) => {
ctx.font = '12px sans-serif';
const tagWidth = ctx.measureText(tag).width + 20;
if (currentX + tagWidth > this.screenWidth - 15) {
currentX = startX;
currentY += tagHeight + tagGap;
}
const isSelected = (type === 'genre' && this.createForm.genre === tag) ||
(type === 'rewrite' && this.selectedRewriteTag === index) ||
(type === 'continue' && this.selectedContinueTag === index);
if (isSelected) {
const gradient = ctx.createLinearGradient(currentX, currentY, currentX + tagWidth, currentY);
gradient.addColorStop(0, '#a855f7');
gradient.addColorStop(1, '#ec4899');
ctx.fillStyle = gradient;
} else {
ctx.fillStyle = 'rgba(255,255,255,0.1)';
}
this.roundRect(ctx, currentX, currentY, tagWidth, tagHeight, 15);
ctx.fill();
if (!isSelected) {
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
ctx.lineWidth = 1;
this.roundRect(ctx, currentX, currentY, tagWidth, tagHeight, 15);
ctx.stroke();
}
ctx.fillStyle = '#ffffff';
ctx.textAlign = 'center';
ctx.fillText(tag, currentX + tagWidth / 2, currentY + 20);
this.tagRects[type].push({
x: currentX,
y: currentY + this.scrollY,
width: tagWidth,
height: tagHeight,
index,
value: tag
});
currentX += tagWidth + tagGap;
});
}
renderInputBox(ctx, x, y, width, height, placeholder, field) {
ctx.fillStyle = 'rgba(255,255,255,0.08)';
this.roundRect(ctx, x, y, width, height, 12);
ctx.fill();
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
ctx.lineWidth = 1;
this.roundRect(ctx, x, y, width, height, 12);
ctx.stroke();
ctx.font = '13px sans-serif';
ctx.textAlign = 'left';
if (this.createForm[field]) {
ctx.fillStyle = '#ffffff';
ctx.fillText(this.createForm[field], x + 15, y + height / 2 + 5);
} else {
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.fillText(placeholder, x + 15, y + height / 2 + 5);
}
if (!this.inputRects) this.inputRects = {};
this.inputRects[field] = { x, y: y + this.scrollY, width, height, field };
}
renderStoryList(ctx, startY, type) {
const padding = 15;
const cardHeight = 70;
const cardGap = 10;
if (!this.storyRects) this.storyRects = {};
this.storyRects[type] = [];
if (this.recentStories.length === 0) {
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('暂无游玩记录,去首页体验故事吧', this.screenWidth / 2, startY + 40);
return;
}
this.recentStories.forEach((story, index) => {
const y = startY + index * (cardHeight + cardGap);
const isSelected = this.selectedStory?.id === story.id;
// 卡片背景
if (isSelected) {
ctx.fillStyle = 'rgba(168, 85, 247, 0.2)';
} else {
ctx.fillStyle = 'rgba(255,255,255,0.06)';
}
this.roundRect(ctx, padding, y, this.screenWidth - padding * 2, cardHeight, 12);
ctx.fill();
if (isSelected) {
ctx.strokeStyle = '#a855f7';
ctx.lineWidth = 2;
this.roundRect(ctx, padding, y, this.screenWidth - padding * 2, cardHeight, 12);
ctx.stroke();
}
// 封面占位
const coverSize = 50;
ctx.fillStyle = 'rgba(255,255,255,0.1)';
this.roundRect(ctx, padding + 10, y + 10, coverSize, coverSize, 8);
ctx.fill();
// 故事标题
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 14px sans-serif';
ctx.textAlign = 'left';
const title = story.title?.length > 12 ? story.title.substring(0, 12) + '...' : story.title;
ctx.fillText(title || '未知故事', padding + 70, y + 28);
// 分类和进度
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.font = '11px sans-serif';
ctx.fillText(`${story.category || '未分类'} · ${story.progress || '进行中'}`, padding + 70, y + 50);
// 选择按钮
const btnX = this.screenWidth - padding - 60;
ctx.fillStyle = isSelected ? '#a855f7' : 'rgba(255,255,255,0.2)';
this.roundRect(ctx, btnX, y + 20, 50, 30, 15);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = '11px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(isSelected ? '已选' : '选择', btnX + 25, y + 40);
this.storyRects[type].push({
x: padding,
y: y + this.scrollY,
width: this.screenWidth - padding * 2,
height: cardHeight,
story
});
});
// 开始按钮
if (this.selectedStory) {
const btnY = startY + this.recentStories.length * (cardHeight + cardGap) + 20;
const btnGradient = ctx.createLinearGradient(padding, btnY, this.screenWidth - padding, btnY);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, padding, btnY, this.screenWidth - padding * 2, 48, 24);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 15px sans-serif';
ctx.textAlign = 'center';
const btnText = type === 'rewrite' ? '✨ 开始AI改写' : '✨ 开始AI续写';
ctx.fillText(btnText, this.screenWidth / 2, btnY + 30);
this.actionBtnRect = {
x: padding,
y: btnY + this.scrollY,
width: this.screenWidth - padding * 2,
height: 48,
type
};
}
}
roundRect(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
onTouchStart(e) {
const touch = e.touches[0];
this.lastTouchY = touch.clientY;
this.touchStartY = touch.clientY;
this.hasMoved = false;
if (touch.clientY > 160) {
this.isDragging = true;
}
}
onTouchMove(e) {
if (!this.isDragging) return;
const touch = e.touches[0];
const deltaY = this.lastTouchY - touch.clientY;
if (Math.abs(deltaY) > 3) {
this.hasMoved = true;
}
this.scrollY += deltaY;
this.scrollY = Math.max(0, Math.min(this.scrollY, this.maxScrollY));
this.lastTouchY = touch.clientY;
}
onTouchEnd(e) {
this.isDragging = false;
if (this.hasMoved) return;
const touch = e.changedTouches[0];
const x = touch.clientX;
const y = touch.clientY;
// 返回按钮
if (y < 60 && x < 80) {
this.main.sceneManager.switchScene('home');
return;
}
// 配额按钮
if (this.quotaBtnRect && this.isInRect(x, y, this.quotaBtnRect)) {
this.showQuotaModal();
return;
}
// Tab切换
if (this.tabRects) {
for (const tab of this.tabRects) {
if (this.isInRect(x, y, tab)) {
if (this.currentTab !== tab.index) {
this.currentTab = tab.index;
this.scrollY = 0;
this.selectedStory = null;
this.calculateMaxScroll();
}
return;
}
}
}
// 调整y坐标考虑滚动
const scrolledY = y + this.scrollY;
// 标签点击
if (this.tagRects) {
const tagType = this.currentTab === 0 ? 'rewrite' : this.currentTab === 1 ? 'continue' : 'genre';
const tags = this.tagRects[tagType];
if (tags) {
for (const tag of tags) {
if (this.isInRect(x, scrolledY, tag)) {
this.handleTagSelect(tagType, tag);
return;
}
}
}
}
// 输入框点击创作Tab
if (this.currentTab === 2 && this.inputRects) {
for (const key in this.inputRects) {
const rect = this.inputRects[key];
if (this.isInRect(x, scrolledY, rect)) {
this.showInputModal(rect.field);
return;
}
}
}
// 故事列表点击
if (this.currentTab < 2 && this.storyRects) {
const type = this.currentTab === 0 ? 'rewrite' : 'continue';
const stories = this.storyRects[type];
if (stories) {
for (const rect of stories) {
if (this.isInRect(x, scrolledY, rect)) {
this.selectedStory = rect.story;
return;
}
}
}
}
// 操作按钮
if (this.actionBtnRect && this.isInRect(x, scrolledY, this.actionBtnRect)) {
this.handleAction(this.actionBtnRect.type);
return;
}
// 创作按钮
if (this.currentTab === 2 && this.createBtnRect && this.isInRect(x, scrolledY, this.createBtnRect)) {
this.handleCreate();
return;
}
}
isInRect(x, y, rect) {
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
}
handleTagSelect(type, tag) {
if (type === 'genre') {
this.createForm.genre = tag.value;
} else if (type === 'rewrite') {
this.selectedRewriteTag = tag.index;
} else if (type === 'continue') {
this.selectedContinueTag = tag.index;
}
}
showInputModal(field) {
const titles = {
keywords: '输入故事关键词',
protagonist: '输入主角设定',
conflict: '输入核心冲突'
};
wx.showModal({
title: titles[field],
editable: true,
placeholderText: '请输入...',
content: this.createForm[field] || '',
success: (res) => {
if (res.confirm && res.content) {
this.createForm[field] = res.content;
}
}
});
}
showQuotaModal() {
wx.showModal({
title: 'AI创作次数',
content: `今日剩余${this.quota.daily - this.quota.used}\n购买次数${this.quota.purchased}\n\n观看广告可获得1次`,
confirmText: '看广告',
success: (res) => {
if (res.confirm) {
this.watchAdForQuota();
}
}
});
}
watchAdForQuota() {
wx.showToast({ title: '获得1次AI次数', icon: 'success' });
this.quota.purchased += 1;
}
handleAction(type) {
if (!this.selectedStory) {
wx.showToast({ title: '请先选择故事', icon: 'none' });
return;
}
const remaining = this.quota.daily - this.quota.used + this.quota.purchased;
if (remaining <= 0) {
this.showQuotaModal();
return;
}
if (type === 'rewrite') {
this.startRewrite();
} else {
this.startContinue();
}
}
startRewrite() {
const tag = this.selectedRewriteTag !== undefined ? this.rewriteTags[this.selectedRewriteTag] : '';
wx.showModal({
title: 'AI改写',
content: '确定要改写这个故事的结局吗?',
editable: true,
placeholderText: tag || '输入改写方向(可选)',
success: async (res) => {
if (res.confirm) {
wx.showLoading({ title: 'AI创作中...' });
try {
const result = await this.main.storyManager.rewriteEnding(
this.selectedStory.id,
{ name: '当前结局', content: '' },
res.content || tag || '改写结局'
);
wx.hideLoading();
if (result) {
this.quota.used += 1;
this.main.sceneManager.switchScene('story', {
storyId: this.selectedStory.id,
aiContent: result
});
}
} catch (e) {
wx.hideLoading();
wx.showToast({ title: '创作失败', icon: 'none' });
}
}
}
});
}
startContinue() {
const tag = this.selectedContinueTag !== undefined ? this.continueTags[this.selectedContinueTag] : '';
wx.showModal({
title: 'AI续写',
content: '确定要让AI续写这个故事吗',
editable: true,
placeholderText: tag || '输入续写方向(可选)',
success: async (res) => {
if (res.confirm) {
wx.showLoading({ title: 'AI创作中...' });
try {
// TODO: 实现续写API
const result = await this.main.storyManager.continueStory(
this.selectedStory.id,
res.content || tag || '续写剧情'
);
wx.hideLoading();
if (result) {
this.quota.used += 1;
this.main.sceneManager.switchScene('story', {
storyId: this.selectedStory.id,
aiContent: result
});
}
} catch (e) {
wx.hideLoading();
wx.showToast({ title: '创作失败', icon: 'none' });
}
}
}
});
}
handleCreate() {
if (!this.createForm.genre) {
wx.showToast({ title: '请选择题材', icon: 'none' });
return;
}
if (!this.createForm.keywords) {
wx.showToast({ title: '请输入关键词', icon: 'none' });
return;
}
const remaining = this.quota.daily - this.quota.used + this.quota.purchased;
if (remaining < 5) {
wx.showModal({
title: '次数不足',
content: 'AI创作需要5次配额当前剩余' + remaining + '次',
confirmText: '获取更多',
success: (res) => {
if (res.confirm) this.showQuotaModal();
}
});
return;
}
wx.showModal({
title: '确认创作',
content: `题材:${this.createForm.genre}\n关键词:${this.createForm.keywords}\n\n将消耗5次AI次数`,
success: async (res) => {
if (res.confirm) {
wx.showLoading({ title: 'AI创作中...', mask: true });
try {
// TODO: 实现完整创作API
const result = await this.main.storyManager.createStory(this.createForm);
wx.hideLoading();
if (result) {
this.quota.used += 5;
wx.showToast({ title: '创作成功!', icon: 'success' });
// 跳转到新故事
setTimeout(() => {
this.main.sceneManager.switchScene('story', { storyId: result.storyId });
}, 1500);
}
} catch (e) {
wx.hideLoading();
wx.showToast({ title: '创作失败', icon: 'none' });
}
}
}
});
}
}

View File

@@ -116,6 +116,24 @@ export default class HomeScene extends BaseScene {
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.fillText('每个选择,都是一个新世界', 20, 75);
// AI创作入口按钮
const btnWidth = 80;
const btnHeight = 32;
const btnX = this.screenWidth - btnWidth - 15;
const btnY = 35;
const btnGradient = ctx.createLinearGradient(btnX, btnY, btnX + btnWidth, btnY);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, btnX, btnY, btnWidth, btnHeight, 16);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 12px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('✨ AI创作', btnX + btnWidth / 2, btnY + 21);
this.aiCreateBtnRect = { x: btnX, y: btnY, width: btnWidth, height: btnHeight };
}
renderCategories(ctx) {
@@ -470,6 +488,15 @@ export default class HomeScene extends BaseScene {
const x = touch.clientX;
const y = touch.clientY;
// 检测AI创作按钮点击
if (this.aiCreateBtnRect) {
const btn = this.aiCreateBtnRect;
if (x >= btn.x && x <= btn.x + btn.width && y >= btn.y && y <= btn.y + btn.height) {
this.main.sceneManager.switchScene('aiCreate');
return;
}
}
// 检测Tab栏点击
if (y > this.screenHeight - 65) {
const tabWidth = this.screenWidth / 3;

View File

@@ -6,6 +6,7 @@ import StoryScene from './StoryScene';
import EndingScene from './EndingScene';
import ProfileScene from './ProfileScene';
import ChapterScene from './ChapterScene';
import AICreateScene from './AICreateScene';
export default class SceneManager {
constructor(main) {
@@ -16,7 +17,8 @@ export default class SceneManager {
story: StoryScene,
ending: EndingScene,
profile: ProfileScene,
chapter: ChapterScene
chapter: ChapterScene,
aiCreate: AICreateScene
};
}