活动介绍

对以下代码进行注释[ContextMenu("绑定骨骼")] public void GetEveryBones() { Transform[] transforms = GetComponentsInChildren<Transform>(); foreach(Transform o in transforms) { if(o.name.StartsWith("裙摆_")||o.name.StartsWith("Arm饰_")||o.name.EndsWith("_5")||o.name.EndsWith("_8")||o.name.StartsWith("后发")) { if(o.childCount>0) { o.gameObject.AddComponent<SpringBone>(); o.gameObject.GetComponent<SpringBone>().child = o.GetChild(0); o.gameObject.GetComponent<SpringBone>().boneAxis = new Vector3(0,1,0); } } } springBones = GetComponentsInChildren<SpringBone>(); }

时间: 2024-02-14 13:15:41 浏览: 119
这段代码是一个用于获取骨骼信息的函数,使用了Unity引擎的ContextMenu特性,可以在Inspector面板中右键调用。 具体注释如下: ``` [ContextMenu("绑定骨骼")] //在Inspector面板中右键菜单 public void GetEveryBones() //获取所有骨骼信息的函数 { Transform[] transforms = GetComponentsInChildren<Transform>(); //获取当前物体及其所有子物体的Transform组件 foreach(Transform o in transforms) //遍历所有Transform组件 { //判断Transform对象名是否符合指定格式,用于筛选需要绑定SpringBone组件的骨骼 if(o.name.StartsWith("裙摆_")||o.name.StartsWith("Arm饰_")||o.name.EndsWith("_5")||o.name.EndsWith("_8")||o.name.StartsWith("后发")) { if(o.childCount>0) //如果该Transform有子物体 { //在该Transform上添加SpringBone组件 o.gameObject.AddComponent<SpringBone>(); //设置SpringBone组件的child字段为其子物体的Transform组件 o.gameObject.GetComponent<SpringBone>().child = o.GetChild(0); //设置SpringBone组件的boneAxis字段为指定的Vector3 o.gameObject.GetComponent<SpringBone>().boneAxis = new Vector3(0,1,0); } } } springBones = GetComponentsInChildren<SpringBone>(); //获取所有子物体中的SpringBone组件 } ```
阅读全文

相关推荐

<script setup lang="ts"> import DrnContextmenu from "@/components/DrnEditorCommon/DrnContextmenu/index.vue"; import DrnContextmenuItem from "@/components/DrnEditorCommon/DrnContextmenuItem/index.vue"; import useStore from "@/store"; import { widgetUtil, stringUtil, jsonUtil } from "doran-web-core"; const { parse } = jsonUtil; import { ref } from "vue"; const { useCopyStore: copyStore } = useStore(); const { renderer } = window.drn; const appStore = parent.appStore; const pageStore = parent.pageStore; const widgetStore = parent.widgetStore; const page = ref(); const contextmenuRef = ref(); const selectWidgetParentRef = ref(); const widgetSource = ref(); const PageComponents = ref(); const widgetType = ref(""); const showEventMenu = ref(false); const widgetParentData: any = ref([]); let currentSelectedWidget: any = ref(); const mountStyle = () => { if (parent?.drn.app.styles?.styleGroup) { window.drn.app.styles.styleGroup = parent.drn.app.styles?.styleGroup; window.drn.app.styles.mountAppStyles(document.head); } if (window.drn.page.styles.styleGroup?.length > 0) { window.drn.page.styles.styleGroup = parent.drn.page.styles?.styleGroup; window.drn.page.styles.mountAppStyles(document.head); } }; const updatePage = () => { // 通过为页面添加和移除class来触发页面重绘 page.value = pageStore.openedPage; if (page.value) { page.value.className = page.value?.className ? page.value?.className : []; page.value.className.push(""); page.value.className.pop(); } mountStyle(); }; page.value = pageStore.openedPage; mountStyle(); appStore.$subscribe(() => { updatePage(); }); pageStore.$subscribe(() => { updatePage(); }); widgetStore.$subscribe(() => { updatePage(); }); const insertWidget = (targetData: any, position: string) => { if (widgetSource.value) { pageStore.openedPage?.moveWidget(widgetSource.value, targetData, position); console.log(widgetSource.value, "111"); widgetStore.selectWidget(widgetSource.value); console.log(widgetStore.selectedWidget, "222"); const prevContainer = document.getElementById(widgetSource.value.id); console.log(widgetSource.value, "+1"); console.log(prevContainer, "+2"); if (prevContainer) { setTimeout(() => { addDropAreaEl(prevContainer); }, 500); } } widgetSource.value = null; }; const drop = (ev: any) => { const realTarget = findTarget(ev.target); const targetId = realTarget?.id; const widget = pageStore.openedPage?.getWidget(targetId); const sourceId = ev.dataTransfer.getData("sourceId"); if (sourceId && sourceId.length > 0) { widgetSource.value = pageStore.openedPage?.getWidget(sourceId); } else { const group = ev.dataTransfer.getData("widget-group"); const type = ev.dataTransfer.getData("widget-type"); if (group && group.length > 0 && type && type.length > 0) { widgetSource.value = widgetUtil.cloneWidgetConfig(type); if (widgetSource.value) { widgetSource.value.id = stringUtil.generateId(); } } } widgetParentData.value = pageStore.openedPage.getParentWidgets( pageStore.openedPage, targetId ); selectWidgetParentRef.value?.show(ev, widget); // const realTarget = findTarget(ev.target); // const targetId = realTarget?.id; // const sourceId = ev.dataTransfer.getData("sourceId"); // let source: any = null; // if (sourceId && sourceId.length > 0) { // source = pageStore.openedPage?.getWidget(sourceId); // } else { // const group = ev.dataTransfer.getData("widget-group"); // const type = ev.dataTransfer.getData("widget-type"); // if (group && group.length > 0 && type && type.length > 0) { // source = widgetUtil.cloneWidgetConfig(type); // if (source) { // source.id = stringUtil.generateId(); // } // } // } // if (source) { // pageStore.openedPage?.moveWidget( // source, // pageStore.openedPage?.getWidget(targetId) // ); // } // ev.target.classList.remove("drn-widget-dragover"); // widgetStore.selectWidget(source); ev.stopPropagation(); }; const dragover = (ev: any) => { ev.preventDefault(); }; const dragstart = (ev: any) => { ev.dataTransfer.setData("sourceId", ev.target.id); ev.dataTransfer.setDragImage(document.createElement("span"), 10, 10); ev.stopPropagation(); }; const dragend = (ev: any) => { const targetId = ev.target.id; const source = pageStore.openedPage?.getWidget(targetId); widgetStore.selectWidget(source); ev.target.classList.remove("drn-widget-dragover"); }; const dragenter = (ev: any) => { ev.target.classList.add("drn-widget-dragover"); }; const dragleave = (ev: any) => { ev.target.classList.remove("drn-widget-dragover"); }; const widgetclick = (ev: any) => { selectedWidget(ev); ev.stopPropagation(); }; // 移除拖拽区域 const removeDropAreaEl = (target: any) => { const dropArea = target.querySelector(".drn-widget-drop-box"); if (dropArea) { target.removeChild(dropArea); } target.classList.remove("selected"); }; // 创建拖拽区域 const addDropAreaEl = (target: any) => { console.log("我走到了+3"); const existingDropArea = target.querySelector(".drn-widget-drop-box"); if (existingDropArea) { console.log("我走到了+4"); return; } console.log("我走到了+5"); const drnDropAreaEl = document.createElement("div"); drnDropAreaEl.className = "drn-widget-drop-box"; drnDropAreaEl.id = "drnDropBox"; const dropImg = new URL("@/assets/img/drop.png", import.meta.url).href; const dropEl = document.createElement("img"); dropEl.id = "drn-widget-dragging_image"; dropEl.className = drn-widget-drop-img-box; dropEl.src = dropImg; drnDropAreaEl.appendChild(dropEl); console.log("我走到了+6"); target.appendChild(drnDropAreaEl); console.log("我走到了+7"); console.log(target); }; //处理放置条件,已经添加则返回,没有则添加, const addDropArea = (ev: any) => { console.log("我走到了+1"); const targetWidget = ev.currentTarget; if (currentSelectedWidget.value) { removeDropAreaEl(currentSelectedWidget.value); } console.log("我走到了+2"); currentSelectedWidget.value = targetWidget; addDropAreaEl(targetWidget); console.log("我走到了+n"); }; const widgetmouseove = (ev: any) => { ev.target.classList.add("drn-widget-item-hover"); ev.stopPropagation(); }; const widgetmouseout = (ev: any) => { ev.stopPropagation(); ev.target.classList.remove("drn-widget-item-hover"); }; const selectedWidget = (ev: any) => { const widget = pageStore.openedPage?.getWidget(ev.target.id); if (widget) { widgetStore.selectWidget(widget); } }; const contextmenu = (ev: any) => { ev.stopPropagation(); ev.preventDefault(); selectedWidget(ev); const widget = pageStore.openedPage?.getWidget(ev.target.id); widgetParentData.value = pageStore.openedPage.getParentWidgets( pageStore.openedPage, ev.target.id ); if (widget) { widgetType.value = widget?.type; showEventMenu.value = widget.events?.length > 0 ? true : false; if (widget) { contextmenuRef.value?.show(ev, widget); } } }; const structureBaseProps = (el: any) => { const clazzes = ["drn-widget-item"]; if (el._needMask) { clazzes.push("drn-widget-mask"); } if (el._needWrapper) { clazzes.push("drn-widget-warpper"); } if (widgetStore.selectedWidget && widgetStore.selectedWidget.id === el.id) { clazzes.push("drn-widget-item-selected"); const prevContainer = document.getElementById( widgetStore.selectedWidget.id ); console.log(widgetStore.selectedWidget, "+1"); console.log(prevContainer, "+2"); if (prevContainer) { const mockEvent = { currentTarget: prevContainer, stopPropagation: () => {}, preventDefault: () => {}, }; console.log("我走到了"); // addDropArea(mockEvent); } } if (!widgetStore.selectedWidget) { document .querySelectorAll(".drn-widget-drop-box") .forEach((el) => el.remove()); } return { draggable: true, ondragstart: dragstart, ondragend: dragend, ondragenter: dragenter, ondragleave: dragleave, ondrop: drop, ondragover: dragover, oncontextmenu: contextmenu, onclick: widgetclick, onmouseover: widgetmouseove, onmouseout: widgetmouseout, class: clazzes.join(" "), title: ${el.name} [${el.id}], }; }; const findTarget = (el: any) => { let currentEl: any = el; while (currentEl && currentEl.classList) { if ( currentEl.classList.contains("drn-widget-item") || currentEl.classList.contains("drn-page-editor") ) { return currentEl; } currentEl = currentEl.parentNode; } }; const getDragImage = () => { let image: any = document.querySelector("#dragging_image"); const draggingImg = new URL("@/assets/img/dragging.png", import.meta.url) .href; if (!image) { image = document.createElement("img"); image.id = "dragging_image"; image.src = draggingImg; image.style = "position:abslute;right:0;bottom:0;z-index:-1;width:0px;"; document.body.append(image); } return image; }; getDragImage(); PageComponents.value = (props: any) => { const { data } = props; return renderer.render(data, structureBaseProps); }; const copyWidget = (widget: any) => { if (widget) { copyStore.copyWidget(widget); } }; const shearWidget = (widget: any) => { if (widget) { pageStore.openedPage.removeWidget(widget.id); copyStore.shearWidget(widget); } }; const pasteWidget = (widget: any) => { if (copyStore.copiedWidgets) { const newWidget = parse(copyStore.copiedWidgets); if (newWidget) { pageStore.openedPage?.moveWidget( newWidget, pageStore.openedPage?.getWidget(widget.id) ); } widgetStore.selectWidget(newWidget); copyStore.pasteWidget(newWidget); } }; const deleteWidget = (widget: any) => { if (widget) { pageStore.openedPage.removeWidget(widget.id); widgetStore.deselectWidget(); } }; const copyWidgetStyles = (widget: any) => { copyStore.copyWidgetStyles(widget); }; const pasteWidgetStyles = (widget: any) => { if (copyStore.copiedWidgetStyle) { pageStore.openedPage?.modifyWidgetStyle( copyStore.copiedWidgetStyle, pageStore.openedPage?.getWidget(widget.id) ); } }; const copyWidgetEvents = (widget: any) => { copyStore.copyWidgetEvents(widget); }; const pasteWidgetEvent = (widget: any) => { if (copyStore.copiedWidgetEvent) { pageStore.openedPage?.modifyWidgetEvent( copyStore.copiedWidgetEvent, pageStore.openedPage?.getWidget(widget.id) ); } }; const selectWidgetEvent = (item: any) => { widgetStore.selectWidget(item); }; const widgetMouseoveEvent = (item: any) => { const prevContainer = document.getElementById(item.id); if (prevContainer) prevContainer.classList.add("drn-widget-item-hover"); }; const widgetMouseoutEvent = (item: any) => { const prevContainer = document.getElementById(item.id); if (prevContainer) prevContainer.classList.remove("drn-widget-item-hover"); }; document.onkeydown = (ev: KeyboardEvent) => { parent.keyBoardEventHandler(ev, 1); }; </script> <template> <drn-contextmenu ref="contextmenuRef"> <template #default="{ data }"> {{ widgetType !== "DrnPage" ? "组件名称:" : "页面名称:" }}{{ data?.name }} <drn-contextmenu-item separator></drn-contextmenu-item> <drn-contextmenu-item v-if="widgetType !== 'DrnPage'" @click="copyWidget(data)" > <template #icon> <drn-icon icon="copy"></drn-icon> </template> 复制 (Ctrl + C) </drn-contextmenu-item> <drn-contextmenu-item v-if="widgetType !== 'DrnPage'" @click="shearWidget(data)" > <template #icon> <drn-icon icon="shear"></drn-icon> </template> 剪切 (Ctrl + X) </drn-contextmenu-item> <drn-contextmenu-item :isAllow="copyStore.copiedWidgets ? true : false" @click="pasteWidget(data)" > <template #icon> <drn-icon icon="paste"></drn-icon> </template> 粘贴 (Ctrl + V) </drn-contextmenu-item> <drn-contextmenu-item v-if="widgetType !== 'DrnPage'" @click="deleteWidget(data)" > <template #icon> <drn-icon icon="trashCan"></drn-icon> </template> 删除 (Ctrl + D) </drn-contextmenu-item> <drn-contextmenu-item separator></drn-contextmenu-item> <drn-contextmenu-item @click="copyWidgetStyles(data)"> <template #icon> <drn-icon icon="copyStyle"></drn-icon> </template> 复制样式 (Ctrl + Shift + C) </drn-contextmenu-item> <drn-contextmenu-item :isAllow="copyStore.copiedWidgetStyle ? true : false" @click="pasteWidgetStyles(data)" > <template #icon> <drn-icon icon="pasteStyle"></drn-icon> </template> 粘贴样式 (Ctrl + Shift + V) </drn-contextmenu-item> <drn-contextmenu-item v-if="showEventMenu" separator ></drn-contextmenu-item> <drn-contextmenu-item v-if="showEventMenu" @click="copyWidgetEvents(data)" > <template #icon> <drn-icon icon="copyEvent"></drn-icon> </template> 复制事件 (Ctrl + Alt + C) </drn-contextmenu-item> <drn-contextmenu-item :isAllow="copyStore.copiedWidgetEvent ? true : false" v-if="showEventMenu" @click="pasteWidgetEvent(data)" > <template #icon> <drn-icon icon="pasteEvent"></drn-icon> </template> 粘贴事件 (Ctrl + Alt + V) </drn-contextmenu-item> <drn-contextmenu-item separator></drn-contextmenu-item> 父级组件 <drn-contextmenu-item separator></drn-contextmenu-item> 0"> <drn-contextmenu-item v-for="item in widgetParentData" @click="selectWidgetEvent(item)" @mouseove="widgetMouseoveEvent(item)" @mouseout="widgetMouseoutEvent(item)" > {{ item.name }} [{{ item.props.general?.proConfig?.uniqueName?.value }}] </drn-contextmenu-item> 暂无父级 </template> </drn-contextmenu> <drn-contextmenu ref="selectWidgetParentRef"> <template #default="{ data }"> {{ widgetType !== "DrnPage" ? "组件名称:" : "页面名称:" }}{{ data?.name }} <drn-contextmenu-item separator></drn-contextmenu-item> 父级组件 <drn-contextmenu-item separator></drn-contextmenu-item> 0"> <drn-contextmenu-item title="中间" @click="insertWidget(item, 'center')" @mouseove="widgetMouseoveEvent(item)" @mouseout="widgetMouseoutEvent(item)" > {{ item.name }} [{{ item.props.general?.proConfig?.uniqueName?.value }}] <drn-icon icon="top" title="顶部" class="drn-icon" @click.stop="insertWidget(item, 'top')" /> <drn-icon icon="bottom" title="底部" class="drn-icon" @click.stop="insertWidget(item, 'bottom')" /> </drn-contextmenu-item> <drn-contextmenu-item separator></drn-contextmenu-item> 暂无父级 </template> </drn-contextmenu> </template> <style scoped></style> 上述方法中insertWidget点击完成后创建拖拽小图标,为啥打印出来已经创建上了,但是在页面上没有渲染,上述insertWidget拖拽已有的组件后出现的放置位置的方法,帮我分析原因并给出解决方法

实验四的界面是图书查询界面Ss.java类代码: import android.content.Intent; import android.os.Bundle; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class Ss extends AppCompatActivity { private EditText editId; private EditText editName; private EditText editAuthor; private static final int item1 = Menu.FIRST; private static final int item2 = Menu.FIRST + 1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ss); // 初始化 EditText editId = findViewById(R.id.edit_id); editName = findViewById(R.id.edit_name); editAuthor = findViewById(R.id.edit_author);//通过ID绑定视图对象 LinearLayout ll = findViewById(R.id.table_layout); registerForContextMenu(ll); // 1清空 - 属性事件响应(XML 按钮需添加 android:onClick="clearByAttribute") // 2清空 - 内部匿名类事件响应 findViewById(R.id.ff_id1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clearFields(); } }); // 3清空 - 监听器接口实现类事件响应 findViewById(R.id.ff_id2).setOnClickListener(new MyClickListener()); // 4清空 - 外部监听器接口实现类事件响应 findViewById(R.id.ff_id3).setOnClickListener(new ExternalClickListener(this)); Button btnBack = findViewById(R.id.btn_back); btnBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Ss.this, Sy.class); startActivity(intent); finish(); } }); } // 1清空对应的属性事件响应方法 public void clearByAttribute(View view) { clearFields(); }//当用户点击按钮就会被执行 // 清空文本框的公共方法 public void clearFields() { if (editId != null) editId.setText(""); if (editName != null) editName.setText(""); if (editAuthor != null) editAuthor.setText(""); } // 内部监听器接口实现类(3清空) private class MyClickListener implements View.OnClickListener { @Override public void onClick(View v) { clearFields(); } } // 外部监听器接口实现类(4清空) @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) { menu.add(0, 1, 0, "删除"); menu.add(0, 2, 0, "修改"); super.onCreateContextMenu(menu, view, info); } @Override public boolean onContextItemSelected(MenuItem item) { if (item.getItemId() == 1) { Toast.makeText(this, "您点击了删除", Toast.LENGTH_LONG).show(); } else if (item.getItemId() == 2) { Toast.makeText(this, "您点击了修改", Toast.LENGTH_LONG).show(); } return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, item1, 0, "关于"); menu.add(0, item2, 0, "退出"); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case item1: Toast.makeText(Ss.this, "姓名:骆树涛。学号:2404224132", Toast.LENGTH_SHORT).show(); break; case item2: this.finish(); break; } return true; } } 图书查询界面的ss.XML布局文件代码: <?xml version="1.0" encoding="utf-8"?> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="图书编号" android:textSize="20dp"/> <EditText android:id="@+id/edit_id" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="图书名称" android:textSize="20dp"/> <EditText android:id="@+id/edit_name" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="图书作者" android:textSize="20dp"/> <EditText android:id="@+id/edit_author" android:layout_width="match_parent" android:layout_height="wrap_content"/> <RadioGroup android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center"> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="中文" android:textSize="20dp"/> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="外文" android:textSize="20dp"/> </RadioGroup> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="查询" android:textSize="20dp"/> <Button android:id="@+id/btn_clar" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="清空" android:textSize="20dp" android:onClick="clearByAttribute"/> <Button android:id="@+id/btn_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="返回" android:textSize="20dp"/> <Button android:id="@+id/ff_id1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="清空" android:textSize="20dp"/> <Button android:id="@+id/ff_id2" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="清空" android:textSize="20dp" /> <Button android:id="@+id/ff_id3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="清空" android:textSize="20dp"/> <TextView android:text="图书编号" android:textSize="15dp"/> <TextView android:text="图书名称" android:textSize="15dp"/> <TextView android:text="图书作者" android:textSize="15dp"/> <TextView android:text="馆藏地点" android:textSize="15dp"/> <TextView android:text="1001" android:textSize="15dp"/> <TextView android:text="Android" android:textSize="15dp"/> <TextView android:text="张三" android:textSize="15dp"/> <TextView android:text="5-423" android:textSize="15dp"/> <TextView android:text="查询结果1条" android:textSize="15dp" android:layout_span="4" android:layout_gravity="center"/> 实验五的有首页界面、图书新增界面、图书详情界面。代码如下 首页Sy.JAVA类代码 import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class Sy extends AppCompatActivity { private static final int item1 = Menu.FIRST; private static final int item2 = Menu.FIRST + 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sy); Button btnAdd = findViewById(R.id.btn_add); Button btnSearch = findViewById(R.id.btn_search); btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Sy.this, Xz.class); startActivity(intent); } }); btnSearch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Sy.this, Ss.class); startActivity(intent); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, item1, 0, "关于"); menu.add(0, item2, 0, "退出"); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case item1: Toast.makeText(Sy.this, "姓名:骆树涛。学号:2404224132", Toast.LENGTH_SHORT).show(); break; case item2: finishAffinity(); break; } return true; } } 首页的sy.XML布局文件代码 <?xml version="1.0" encoding="utf-8"?> <Button android:id="@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新增" android:textSize="20dp"/> <Button android:id="@+id/btn_search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="查询" android:textSize="20dp"/> 图书新增的Xz.Java类代码: import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import androidx.appcompat.app.AppCompatActivity; public class Xz extends AppCompatActivity { private EditText editBookId; private EditText editBookName; private EditText editBookAuthor; private EditText editBookLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.xz); editBookId = findViewById(R.id.edit_book_id); editBookName = findViewById(R.id.edit_book_name); editBookAuthor = findViewById(R.id.edit_book_author); editBookLocation = findViewById(R.id.edit_book_location); Button btnAddBook = findViewById(R.id.btn_add_book); btnAddBook.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String bookId = editBookId.getText().toString(); String bookName = editBookName.getText().toString(); String bookAuthor = editBookAuthor.getText().toString(); String bookLocation = editBookLocation.getText().toString(); Intent intent = new Intent(Xz.this, Xq.class); intent.putExtra("bookId", bookId); intent.putExtra("bookName", bookName); intent.putExtra("bookAuthor", bookAuthor); intent.putExtra("bookLocation", bookLocation); startActivity(intent); } }); } } 图书新增的xz.XML布局文件代码: <?xml version="1.0" encoding="utf-8"?> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="图书编号" android:textSize="20dp"/> <EditText android:id="@+id/edit_book_id" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="图书名称" android:textSize="20dp"/> <EditText android:id="@+id/edit_book_name" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="图书作者" android:textSize="20dp"/> <EditText android:id="@+id/edit_book_author" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="馆藏地点" android:textSize="20dp"/> <EditText android:id="@+id/edit_book_location" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn_add_book" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新增" android:textSize="20dp" android:layout_gravity="center"/> 图书详情的Xq.java类代码: import android.content.Intent; import android.os.Bundle; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class Xq extends AppCompatActivity { private static final int ITEM_HOME = Menu.FIRST; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.xq); TextView tvBookId = findViewById(R.id.tv_book_id); TextView tvBookName = findViewById(R.id.tv_book_name); TextView tvBookAuthor = findViewById(R.id.tv_book_author); TextView tvBookLocation = findViewById(R.id.tv_book_location); Intent intent = getIntent(); String bookId = intent.getStringExtra("bookId"); String bookName = intent.getStringExtra("bookName"); String bookAuthor = intent.getStringExtra("bookAuthor"); String bookLocation = intent.getStringExtra("bookLocation"); tvBookId.setText("图书编号:" + bookId); tvBookName.setText("图书名称:" + bookName); tvBookAuthor.setText("图书作者:" + bookAuthor); tvBookLocation.setText("馆藏地点:" + bookLocation); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, ITEM_HOME, 0, "首页"); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case ITEM_HOME: Intent intent = new Intent(Xq.this, Sy.class); startActivity(intent); finish(); return true; default: return super.onOptionsItemSelected(item); } } } 图书详情的xq.XML布局文件代码: <?xml version="1.0" encoding="utf-8"?> <TextView android:id="@+id/tv_book_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20dp"/> <TextView android:id="@+id/tv_book_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20dp"/> <TextView android:id="@+id/tv_book_author" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20dp"/> <TextView android:id="@+id/tv_book_location" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20dp"/> 在实验4的基础上,新增3个界面,分别是图书管理系统的“首页”、“图书新增”和“图书详情”界面。具体要求如下: (1)首页显示两个按钮,分别是“新增”和“查询”。点击“新增”按钮,跳转到图书新增界面;点击“查询”按钮,调整到图书查询界面(即实验4所完成的界面)。 (2)图书新增界面,设置图书编号、图书名称、图书作者和馆藏地点四个信息的输入框,以及一个“新增”按钮。用户点击新增按钮后,将用户输入的4个信息传递到图书详情页面,并显示图书详情页面。 (3)图书详情页面用于显示用户输入的图书编号、图书名称、图书作者和馆藏地点。 (4)整个应用程序的入口固定设置为“首页”对应的Activity。 (5)完善“图书查询界面”中的"返回"按钮,按钮的作用是回到首页。 (6)将实验3中,图书查询页面的OptionsMenu搬迁到首页程序中。根据题目来规划写个流程图

给出完整的vue3代码,参考下面的代码<template> <el-tabs v-model="activeTab" type="card" closable @tab-remove="removeTab" @tab-click="handleTabClick" > <el-tab-pane v-for="tab in tabs" :key="tab.path" :label="tab.title" :name="tab.path" :closable="tab.path !== '/'" > <template #label> {{ tab.title }} </template> </el-tab-pane> </el-tabs> 关闭 关闭其他标签页 关闭所有标签页 关闭左侧标签页 关闭右侧标签页 </template> <script setup> import { ref, computed, watch, onMounted, onUnmounted } from 'vue' import { useRoute, useRouter } from 'vue-router' import { useTabsStore } from '@/store/tabs' const route = useRoute() const router = useRouter() const tabsStore = useTabsStore() const tabs = computed(() => tabsStore.tabs) const activeTab = ref(route.path) // 右键菜单状态 const contextMenu = ref({ visible: false, top: 0, left: 0, targetPath: null }) // 监听路由变化 watch( () => route.path, (newPath) => { activeTab.value = newPath tabsStore.addTab({path: newPath, title: route.meta.title}) }, {immediate: true} ) // 关闭右键菜单 const closeContextMenu = () => { contextMenu.value.visible = false } // 打开右键菜单 const openContextMenu = (event, path) => { contextMenu.value = { visible: true, top: event.clientY, left: event.clientX, targetPath: path } } // 关闭当前标签页 const closeTab = () => { if (contextMenu.value.targetPath && contextMenu.value.targetPath !== '/') { removeTab(contextMenu.value.targetPath) } closeContextMenu() } // 关闭其他标签页 const closeOtherTabs = () => { if (!contextMenu.value.targetPath) { closeContextMenu() return } const keepTabs = tabs.value.filter(tab => tab.path === '/' || tab.path === contextMenu.value.targetPath ) tabsStore.setTabs(keepTabs) // 如果当前路由不在保留的标签页中,则跳转到目标页 if (!keepTabs.find(tab => tab.path === route.path)) { router.push(contextMenu.value.targetPath) } closeContextMenu() } // 关闭所有标签页(保留主页) const closeAllTabs = () => { const homeTab = tabs.value.find(tab => tab.path === '/') tabsStore.setTabs(homeTab ? [homeTab] : []) // 如果当前不是主页,则跳转到主页 if (route.path !== '/') { router.push('/') } closeContextMenu() } // 关闭左侧标签页 const closeLeftTabs = () => { if (!contextMenu.value.targetPath) { closeContextMenu() return } const targetIndex = tabs.value.findIndex(tab => tab.path === contextMenu.value.targetPath) if (targetIndex <= 0) { closeContextMenu() return } // 保留主页和右侧的标签页(包括当前标签页) const keepTabs = tabs.value.filter((tab, index) => tab.path === '/' || index >= targetIndex ) tabsStore.setTabs(keepTabs) // 如果当前路由不在保留的标签页中,则跳转到目标页 if (!keepTabs.find(tab => tab.path === route.path)) { router.push(contextMenu.value.targetPath) } closeContextMenu() } // 关闭右侧标签页 const closeRightTabs = () => { if (!contextMenu.value.targetPath) { closeContextMenu() return } const targetIndex = tabs.value.findIndex(tab => tab.path === contextMenu.value.targetPath) if (targetIndex === -1 || targetIndex >= tabs.value.length - 1) { closeContextMenu() return } // 保留主页和左侧的标签页(包括当前标签页) const keepTabs = tabs.value.filter((tab, index) => tab.path === '/' || index <= targetIndex ) tabsStore.setTabs(keepTabs) // 如果当前路由不在保留的标签页中,则跳转到目标页 if (!keepTabs.find(tab => tab.path === route.path)) { router.push(contextMenu.value.targetPath) } closeContextMenu() } // 关闭单个标签页 const removeTab = (targetPath) => { if (targetPath === '/') return // 禁止关闭首页 const currentPath = route.path const tabs = tabsStore.tabs let activePath = activeTab.value if (targetPath === activePath) { // 关闭当前激活的标签 const index = tabs.findIndex(tab => tab.path === targetPath) const nextTab = tabs[index + 1] || tabs[index - 1] if (nextTab) { activePath = nextTab.path } else { activePath = '/' } } tabsStore.removeTab(targetPath) if (targetPath === currentPath) { router.push(activePath) } } // 点击标签页切换路由 const handleTabClick = (tab) => { const path = tab.props.name if (path !== route.path) { router.push(path) } } // 全局点击关闭右键菜单 const handleGlobalClick = () => { if (contextMenu.value.visible) { closeContextMenu() } } // 添加全局点击监听 onMounted(() => { document.addEventListener('click', handleGlobalClick) }) // 移除全局点击监听 onUnmounted(() => { document.removeEventListener('click', handleGlobalClick) }) </script> <style scoped> .tabs-bar { height: 5vh; min-height: 40px; background-color: #fff; border-bottom: 1px solid #e6e6e6; padding: 0 10px; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); z-index: 10; position: relative; } :deep(.el-tabs) { height: 100%; } :deep(.el-tabs__header) { margin: 0; border-bottom: none; height: 100%; } :deep(.el-tabs__nav) { border: none !important; } :deep(.el-tabs__item) { height: 32px; line-height: 32px; border: 1px solid #e6e6e6 !important; border-radius: 4px 4px 0 0 !important; margin-right: 4px; background-color: #f5f7fa; transition: all 0.3s; position: relative; } :deep(.el-tabs__item.is-active) { background-color: #fff; border-bottom-color: #fff !important; } :deep(.el-tabs__item:not(.is-active):hover) { color: #409eff; } :deep(.el-tabs__nav-next), :deep(.el-tabs__nav-prev) { line-height: 40px; } .custom-tab-label { height: 100%; width: 100%; display: flex; align-items: center; justify-content: center; } /* 右键菜单样式 */ .context-menu { position: fixed; background-color: #fff; border: 1px solid #e6e6e6; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); z-index: 2000; min-width: 120px; } .menu-item { padding: 8px 12px; font-size: 13px; cursor: pointer; } .menu-item:hover { background-color: #f5f7fa; color: #409eff; } </style> 并结合上述代码,给完整的VUE3代码

//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- using UnityEngine; using System.Collections.Generic; /// /// UI Panel is responsible for collecting, sorting and updating widgets in addition to generating widgets' geometry. /// [ExecuteInEditMode] [AddComponentMenu("NGUI/UI/NGUI Panel")] public class UIPanel : UIRect { /// /// List of active panels. /// static public List<UIPanel> list = new List<UIPanel>(); public enum RenderQueue { Automatic, StartAt, Explicit, } public delegate void OnGeometryUpdated (); /// /// Notification triggered when the panel's geometry get rebuilt. It's mainly here for debugging purposes. /// public OnGeometryUpdated onGeometryUpdated; /// /// Whether this panel will show up in the panel tool (set this to 'false' for dynamically created temporary panels) /// public bool showInPanelTool = true; /// /// Whether normals and tangents will be generated for all meshes /// public bool generateNormals = false; /// /// Whether widgets drawn by this panel are static (won't move). This will improve performance. /// public bool widgetsAreStatic = false; /// /// Whether widgets will be culled while the panel is being dragged. /// Having this on improves performance, but turning it off will reduce garbage collection. /// public bool cullWhileDragging = true; /// /// Optimization flag. Makes the assumption that the panel's geometry /// will always be on screen and the bounds don't need to be re-calculated. /// public bool alwaysOnScreen = false; /// /// By default, non-clipped panels use the camera's bounds, and the panel's position has no effect. /// If you want the panel's position to actually be used with anchors, set this field to 'true'. /// public bool anchorOffset = false; /// /// Whether the soft border will be used as padding. /// public bool softBorderPadding = true; /// /// By default all panels manage render queues of their draw calls themselves by incrementing them /// so that the geometry is drawn in the proper order. You can alter this behaviour. /// public RenderQueue renderQueue = RenderQueue.Automatic; /// /// Render queue used by the panel. The default value of '3000' is the equivalent of "Transparent". /// This property is only used if 'renderQueue' is set to something other than "Automatic". /// public int startingRenderQueue = 3000; /// /// List of widgets managed by this panel. Do not attempt to modify this list yourself. /// [System.NonSerialized] public List<UIWidget> widgets = new List<UIWidget>(); /// /// List of draw calls created by this panel. Do not attempt to modify this list yourself. /// [System.NonSerialized] public List<UIDrawCall> drawCalls = new List<UIDrawCall>(); /// /// Matrix that will transform the specified world coordinates to relative-to-panel coordinates. /// [System.NonSerialized] public Matrix4x4 worldToLocal = Matrix4x4.identity; /// /// Cached clip range passed to the draw call's shader. /// [System.NonSerialized] public Vector4 drawCallClipRange = new Vector4(0f, 0f, 1f, 1f); public delegate void OnClippingMoved (UIPanel panel); /// /// Event callback that's triggered when the panel's clip region gets moved. /// public OnClippingMoved onClipMove; // Clip texture feature contributed by the community: http://www.tasharen.com/forum/index.php?topic=9268.0 [HideInInspector][SerializeField] Texture2D mClipTexture = null; // Panel's alpha (affects the alpha of all widgets) [HideInInspector][SerializeField] float mAlpha = 1f; // Clipping rectangle [HideInInspector][SerializeField] UIDrawCall.Clipping mClipping = UIDrawCall.Clipping.None; [HideInInspector][SerializeField] Vector4 mClipRange = new Vector4(0f, 0f, 300f, 200f); [HideInInspector][SerializeField] Vector2 mClipSoftness = new Vector2(4f, 4f); [HideInInspector][SerializeField] int mDepth = 0; [HideInInspector][SerializeField] int mSortingOrder = 0; // Whether a full rebuild of geometry buffers is required bool mRebuild = false; bool mResized = false; [SerializeField] Vector2 mClipOffset = Vector2.zero; float mCullTime = 0f; float mUpdateTime = 0f; int mMatrixFrame = -1; int mAlphaFrameID = 0; int mLayer = -1; // Values used for visibility checks static float[] mTemp = new float[4]; Vector2 mMin = Vector2.zero; Vector2 mMax = Vector2.zero; bool mHalfPixelOffset = false; bool mSortWidgets = false; bool mUpdateScroll = false; /// /// Helper property that returns the first unused depth value. /// static public int nextUnusedDepth { get { int highest = int.MinValue; for (int i = 0, imax = list.Count; i < imax; ++i) highest = Mathf.Max(highest, list[i].depth); return (highest == int.MinValue) ? 0 : highest + 1; } } /// /// Whether the rectangle can be anchored. /// public override bool canBeAnchored { get { return mClipping != UIDrawCall.Clipping.None; } } /// /// Panel's alpha affects everything drawn by the panel. /// public override float alpha { get { return mAlpha; } set { float val = Mathf.Clamp01(value); if (mAlpha != val) { mAlphaFrameID = -1; mResized = true; mAlpha = val; SetDirty(); } } } /// /// Panels can have their own depth value that will change the order with which everything they manage gets drawn. /// public int depth { get { return mDepth; } set { if (mDepth != value) { mDepth = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif list.Sort(CompareFunc); } } } /// /// Sorting order value for the panel's draw calls, to be used with Unity's 2D system. /// public int sortingOrder { get { return mSortingOrder; } set { if (mSortingOrder != value) { mSortingOrder = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif UpdateDrawCalls(); } } } /// /// Function that can be used to depth-sort panels. /// static public int CompareFunc (UIPanel a, UIPanel b) { if (a != b && a != null && b != null) { if (a.mDepth < b.mDepth) return -1; if (a.mDepth > b.mDepth) return 1; return (a.GetInstanceID() < b.GetInstanceID()) ? -1 : 1; } return 0; } /// /// Panel's width in pixels. /// public float width { get { return GetViewSize().x; } } /// /// Panel's height in pixels. /// public float height { get { return GetViewSize().y; } } /// /// Whether the panel's drawn geometry needs to be offset by a half-pixel. /// public bool halfPixelOffset { get { return mHalfPixelOffset; } } /// /// Whether the camera is used to draw UI geometry. /// #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 public bool usedForUI { get { return (anchorCamera != null && mCam.isOrthoGraphic); } } #else public bool usedForUI { get { return (anchorCamera != null && mCam.orthographic); } } #endif /// /// Directx9 pixel offset, used for drawing. /// public Vector3 drawCallOffset { get { #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 if (anchorCamera != null && mCam.isOrthoGraphic) #else if (anchorCamera != null && mCam.orthographic) #endif { Vector2 size = GetWindowSize(); float pixelSize = (root != null) ? root.pixelSizeAdjustment : 1f; float mod = (pixelSize / size.y) / mCam.orthographicSize; bool x = mHalfPixelOffset; bool y = mHalfPixelOffset; if ((Mathf.RoundToInt(size.x) & 1) == 1) x = !x; if ((Mathf.RoundToInt(size.y) & 1) == 1) y = !y; return new Vector3(x ? -mod : 0f, y ? mod : 0f); } return Vector3.zero; } } /// /// Clipping method used by all draw calls. /// public UIDrawCall.Clipping clipping { get { return mClipping; } set { if (mClipping != value) { mResized = true; mClipping = value; mMatrixFrame = -1; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } UIPanel mParentPanel = null; /// /// Reference to the parent panel, if any. /// public UIPanel parentPanel { get { return mParentPanel; } } /// /// Number of times the panel's contents get clipped. /// public int clipCount { get { int count = 0; UIPanel p = this; while (p != null) { if (p.mClipping == UIDrawCall.Clipping.SoftClip || p.mClipping == UIDrawCall.Clipping.TextureMask) ++count; p = p.mParentPanel; } return count; } } /// /// Whether the panel will actually perform clipping of children. /// public bool hasClipping { get { return mClipping == UIDrawCall.Clipping.SoftClip || mClipping == UIDrawCall.Clipping.TextureMask; } } /// /// Whether the panel will actually perform clipping of children. /// public bool hasCumulativeClipping { get { return clipCount != 0; } } [System.Obsolete("Use 'hasClipping' or 'hasCumulativeClipping' instead")] public bool clipsChildren { get { return hasCumulativeClipping; } } /// /// Clipping area offset used to make it possible to move clipped panels (scroll views) efficiently. /// Scroll views move by adjusting the clip offset by one value, and the transform position by the inverse. /// This makes it possible to not have to rebuild the geometry, greatly improving performance. /// public Vector2 clipOffset { get { return mClipOffset; } set { if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f || Mathf.Abs(mClipOffset.y - value.y) > 0.001f) { mClipOffset = value; InvalidateClipping(); // Call the event delegate if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// /// Invalidate the panel's clipping, calling child panels in turn. /// void InvalidateClipping () { mResized = true; mMatrixFrame = -1; mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f; for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p != this && p.parentPanel == this) p.InvalidateClipping(); } } /// /// Texture used to clip the region. /// public Texture2D clipTexture { get { return mClipTexture; } set { if (mClipTexture != value) { mClipTexture = value; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// /// Clipping position (XY) and size (ZW). /// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead. /// [System.Obsolete("Use 'finalClipRegion' or 'baseClipRegion' instead")] public Vector4 clipRange { get { return baseClipRegion; } set { baseClipRegion = value; } } /// /// Clipping position (XY) and size (ZW). /// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead. /// public Vector4 baseClipRegion { get { return mClipRange; } set { if (Mathf.Abs(mClipRange.x - value.x) > 0.001f || Mathf.Abs(mClipRange.y - value.y) > 0.001f || Mathf.Abs(mClipRange.z - value.z) > 0.001f || Mathf.Abs(mClipRange.w - value.w) > 0.001f) { mResized = true; mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f; mClipRange = value; mMatrixFrame = -1; UIScrollView sv = GetComponent<UIScrollView>(); if (sv != null) sv.UpdatePosition(); if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// /// Final clipping region after the offset has been taken into consideration. XY = center, ZW = size. /// public Vector4 finalClipRegion { get { Vector2 size = GetViewSize(); if (mClipping != UIDrawCall.Clipping.None) { return new Vector4(mClipRange.x + mClipOffset.x, mClipRange.y + mClipOffset.y, size.x, size.y); } return new Vector4(0f, 0f, size.x, size.y); } } /// /// Clipping softness is used if the clipped style is set to "Soft". /// public Vector2 clipSoftness { get { return mClipSoftness; } set { if (mClipSoftness != value) { mClipSoftness = value; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } // Temporary variable to avoid GC allocation static Vector3[] mCorners = new Vector3[4]; /// /// Local-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right. /// public override Vector3[] localCorners { get { if (mClipping == UIDrawCall.Clipping.None) { Vector3[] corners = worldCorners; Transform wt = cachedTransform; for (int i = 0; i < 4; ++i) corners[i] = wt.InverseTransformPoint(corners[i]); return corners; } else { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; mCorners[0] = new Vector3(x0, y0); mCorners[1] = new Vector3(x0, y1); mCorners[2] = new Vector3(x1, y1); mCorners[3] = new Vector3(x1, y0); } return mCorners; } } /// /// World-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right. /// public override Vector3[] worldCorners { get { if (mClipping != UIDrawCall.Clipping.None) { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; Transform wt = cachedTransform; mCorners[0] = wt.TransformPoint(x0, y0, 0f); mCorners[1] = wt.TransformPoint(x0, y1, 0f); mCorners[2] = wt.TransformPoint(x1, y1, 0f); mCorners[3] = wt.TransformPoint(x1, y0, 0f); } else if (anchorCamera != null) { Vector3[] corners = mCam.GetWorldCorners(cameraRayDistance); //if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform)) //{ // Vector3 off = cachedTransform.position; // for (int i = 0; i < 4; ++i) // corners[i] += off; //} return corners; } else { Vector2 size = GetViewSize(); float x0 = -0.5f * size.x; float y0 = -0.5f * size.y; float x1 = x0 + size.x; float y1 = y0 + size.y; mCorners[0] = new Vector3(x0, y0); mCorners[1] = new Vector3(x0, y1); mCorners[2] = new Vector3(x1, y1); mCorners[3] = new Vector3(x1, y0); if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform)) { Vector3 off = cachedTransform.position; for (int i = 0; i < 4; ++i) mCorners[i] += off; } } return mCorners; } } /// /// Get the sides of the rectangle relative to the specified transform. /// The order is left, top, right, bottom. /// public override Vector3[] GetSides (Transform relativeTo) { if (mClipping != UIDrawCall.Clipping.None) { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; float hx = (x0 + x1) * 0.5f; float hy = (y0 + y1) * 0.5f; Transform wt = cachedTransform; mSides[0] = wt.TransformPoint(x0, hy, 0f); mSides[1] = wt.TransformPoint(hx, y1, 0f); mSides[2] = wt.TransformPoint(x1, hy, 0f); mSides[3] = wt.TransformPoint(hx, y0, 0f); if (relativeTo != null) { for (int i = 0; i < 4; ++i) mSides[i] = relativeTo.InverseTransformPoint(mSides[i]); } return mSides; } else if (anchorCamera != null && anchorOffset) { Vector3[] sides = mCam.GetSides(cameraRayDistance); Vector3 off = cachedTransform.position; for (int i = 0; i < 4; ++i) sides[i] += off; if (relativeTo != null) { for (int i = 0; i < 4; ++i) sides[i] = relativeTo.InverseTransformPoint(sides[i]); } return sides; } return base.GetSides(relativeTo); } /// /// Invalidating the panel should reset its alpha. /// public override void Invalidate (bool includeChildren) { mAlphaFrameID = -1; base.Invalidate(includeChildren); } /// /// Widget's final alpha, after taking the panel's alpha into account. /// public override float CalculateFinalAlpha (int frameID) { #if UNITY_EDITOR if (mAlphaFrameID != frameID || !Application.isPlaying) #else if (mAlphaFrameID != frameID) #endif { mAlphaFrameID = frameID; UIRect pt = parent; finalAlpha = (parent != null) ? pt.CalculateFinalAlpha(frameID) * mAlpha : mAlpha; } return finalAlpha; } /// /// Set the panel's rectangle. /// public override void SetRect (float x, float y, float width, float height) { int finalWidth = Mathf.FloorToInt(width + 0.5f); int finalHeight = Mathf.FloorToInt(height + 0.5f); finalWidth = ((finalWidth >> 1) << 1); finalHeight = ((finalHeight >> 1) << 1); Transform t = cachedTransform; Vector3 pos = t.localPosition; pos.x = Mathf.Floor(x + 0.5f); pos.y = Mathf.Floor(y + 0.5f); if (finalWidth < 2) finalWidth = 2; if (finalHeight < 2) finalHeight = 2; baseClipRegion = new Vector4(pos.x, pos.y, finalWidth, finalHeight); if (isAnchored) { t = t.parent; if (leftAnchor.target) leftAnchor.SetHorizontal(t, x); if (rightAnchor.target) rightAnchor.SetHorizontal(t, x + width); if (bottomAnchor.target) bottomAnchor.SetVertical(t, y); if (topAnchor.target) topAnchor.SetVertical(t, y + height); #if UNITY_EDITOR NGUITools.SetDirty(this); #endif } } /// /// Returns whether the specified rectangle is visible by the panel. The coordinates must be in world space. /// #if UNITY_FLASH public bool IsVisible (Vector3 aa, Vector3 bb, Vector3 cc, Vector3 dd) #else public bool IsVisible (Vector3 a, Vector3 b, Vector3 c, Vector3 d) #endif { UpdateTransformMatrix(); // Transform the specified points from world space to local space #if UNITY_FLASH // http://www.tasharen.com/forum/index.php?topic=11390.0 Vector3 a = worldToLocal.MultiplyPoint3x4(aa); Vector3 b = worldToLocal.MultiplyPoint3x4(bb); Vector3 c = worldToLocal.MultiplyPoint3x4(cc); Vector3 d = worldToLocal.MultiplyPoint3x4(dd); #else a = worldToLocal.MultiplyPoint3x4(a); b = worldToLocal.MultiplyPoint3x4(b); c = worldToLocal.MultiplyPoint3x4(c); d = worldToLocal.MultiplyPoint3x4(d); #endif mTemp[0] = a.x; mTemp[1] = b.x; mTemp[2] = c.x; mTemp[3] = d.x; float minX = Mathf.Min(mTemp); float maxX = Mathf.Max(mTemp); mTemp[0] = a.y; mTemp[1] = b.y; mTemp[2] = c.y; mTemp[3] = d.y; float minY = Mathf.Min(mTemp); float maxY = Mathf.Max(mTemp); if (maxX < mMin.x) return false; if (maxY < mMin.y) return false; if (minX > mMax.x) return false; if (minY > mMax.y) return false; return true; } /// /// Returns whether the specified world position is within the panel's bounds determined by the clipping rect. /// public bool IsVisible (Vector3 worldPos) { if (mAlpha < 0.001f) return false; if (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip) return true; UpdateTransformMatrix(); Vector3 pos = worldToLocal.MultiplyPoint3x4(worldPos); if (pos.x < mMin.x) return false; if (pos.y < mMin.y) return false; if (pos.x > mMax.x) return false; if (pos.y > mMax.y) return false; return true; } /// /// Returns whether the specified widget is visible by the panel. /// public bool IsVisible (UIWidget w) { UIPanel p = this; Vector3[] corners = null; while (p != null) { if ((p.mClipping == UIDrawCall.Clipping.None || p.mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen) { p = p.mParentPanel; continue; } if (corners == null) corners = w.worldCorners; if (!p.IsVisible(corners[0], corners[1], corners[2], corners[3])) return false; p = p.mParentPanel; } return true; } /// /// Whether the specified widget is going to be affected by this panel in any way. /// public bool Affects (UIWidget w) { if (w == null) return false; UIPanel expected = w.panel; if (expected == null) return false; UIPanel p = this; while (p != null) { if (p == expected) return true; if (!p.hasCumulativeClipping) return false; p = p.mParentPanel; } return false; } /// /// Causes all draw calls to be re-created on the next update. /// [ContextMenu("Force Refresh")] public void RebuildAllDrawCalls () { mRebuild = true; } /// /// Invalidate the panel's draw calls, forcing them to be rebuilt on the next update. /// This call also affects all children. /// public void SetDirty () { for (int i = 0, imax = drawCalls.Count; i < imax; ++i) drawCalls[i].isDirty = true; Invalidate(true); } /// /// Cache components. /// void Awake () { mGo = gameObject; mTrans = transform; mHalfPixelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.XBOX360 || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); // Only DirectX 9 needs the half-pixel offset if (mHalfPixelOffset && SystemInfo.graphicsDeviceVersion.Contains("Direct3D")) mHalfPixelOffset = (SystemInfo.graphicsShaderLevel < 40); } /// /// Find the parent panel, if we have one. /// void FindParent () { Transform parent = cachedTransform.parent; mParentPanel = (parent != null) ? NGUITools.FindInParents<UIPanel>(parent.gameObject) : null; } /// /// Find the parent panel, if we have one. /// public override void ParentHasChanged () { base.ParentHasChanged(); FindParent(); } /// /// Layer is used to ensure that if it changes, widgets get moved as well. /// protected override void OnStart () { mLayer = mGo.layer; } /// /// Reset the frame IDs. /// protected override void OnEnable () { mRebuild = true; mAlphaFrameID = -1; mMatrixFrame = -1; OnStart(); base.OnEnable(); mMatrixFrame = -1; } /// /// Mark all widgets as having been changed so the draw calls get re-created. /// protected override void OnInit () { if (list.Contains(this)) return; base.OnInit(); FindParent(); // Apparently having a rigidbody helps #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 if (rigidbody == null && mParentPanel == null) #else if (GetComponent<Rigidbody>() == null && mParentPanel == null) #endif { UICamera uic = (anchorCamera != null) ? mCam.GetComponent<UICamera>() : null; if (uic != null) { if (uic.eventType == UICamera.EventType.UI_3D || uic.eventType == UICamera.EventType.World_3D) { Rigidbody rb = gameObject.AddComponent<Rigidbody>(); rb.isKinematic = true; rb.useGravity = false; } // It's unclear if this helps 2D physics or not, so leaving it disabled for now. // Note that when enabling this, the 'if (rigidbody == null)' statement above should be adjusted as well. //else //{ // Rigidbody2D rb = gameObject.AddComponent<Rigidbody2D>(); // rb.isKinematic = true; //} } } mRebuild = true; mAlphaFrameID = -1; mMatrixFrame = -1; list.Add(this); list.Sort(CompareFunc); } /// /// Destroy all draw calls we've created when this script gets disabled. /// protected override void OnDisable () { for (int i = 0, imax = drawCalls.Count; i < imax; ++i) { UIDrawCall dc = drawCalls[i]; UIDrawCall.Destroy(dc); } drawCalls.Clear(); list.Remove(this); mAlphaFrameID = -1; mMatrixFrame = -1; if (list.Count == 0) { UIDrawCall.ReleaseAll(); mUpdateFrame = -1; } base.OnDisable(); } /// /// Update the world-to-local transform matrix as well as clipping bounds. /// void UpdateTransformMatrix () { int fc = Time.frameCount; if (mMatrixFrame != fc) { mMatrixFrame = fc; worldToLocal = cachedTransform.worldToLocalMatrix; Vector2 size = GetViewSize() * 0.5f; float x = mClipOffset.x + mClipRange.x; float y = mClipOffset.y + mClipRange.y; mMin.x = x - size.x; mMin.y = y - size.y; mMax.x = x + size.x; mMax.y = y + size.y; } } /// /// Update the edges after the anchors have been updated. /// protected override void OnAnchor () { // No clipping = no edges to anchor if (mClipping == UIDrawCall.Clipping.None) return; Transform trans = cachedTransform; Transform parent = trans.parent; Vector2 size = GetViewSize(); Vector2 offset = trans.localPosition; float lt, bt, rt, tt; // Attempt to fast-path if all anchors match if (leftAnchor.target == bottomAnchor.target && leftAnchor.target == rightAnchor.target && leftAnchor.target == topAnchor.target) { Vector3[] sides = leftAnchor.GetSides(parent); if (sides != null) { lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute; rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute; bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute; tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute; } else { // Anchored to a single transform Vector2 lp = GetLocalPos(leftAnchor, parent); lt = lp.x + leftAnchor.absolute; bt = lp.y + bottomAnchor.absolute; rt = lp.x + rightAnchor.absolute; tt = lp.y + topAnchor.absolute; } } else { // Left anchor point if (leftAnchor.target) { Vector3[] sides = leftAnchor.GetSides(parent); if (sides != null) { lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute; } else { lt = GetLocalPos(leftAnchor, parent).x + leftAnchor.absolute; } } else lt = mClipRange.x - 0.5f * size.x; // Right anchor point if (rightAnchor.target) { Vector3[] sides = rightAnchor.GetSides(parent); if (sides != null) { rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute; } else { rt = GetLocalPos(rightAnchor, parent).x + rightAnchor.absolute; } } else rt = mClipRange.x + 0.5f * size.x; // Bottom anchor point if (bottomAnchor.target) { Vector3[] sides = bottomAnchor.GetSides(parent); if (sides != null) { bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute; } else { bt = GetLocalPos(bottomAnchor, parent).y + bottomAnchor.absolute; } } else bt = mClipRange.y - 0.5f * size.y; // Top anchor point if (topAnchor.target) { Vector3[] sides = topAnchor.GetSides(parent); if (sides != null) { tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute; } else { tt = GetLocalPos(topAnchor, parent).y + topAnchor.absolute; } } else tt = mClipRange.y + 0.5f * size.y; } // Take the offset into consideration lt -= offset.x + mClipOffset.x; rt -= offset.x + mClipOffset.x; bt -= offset.y + mClipOffset.y; tt -= offset.y + mClipOffset.y; // Calculate the new position, width and height float newX = Mathf.Lerp(lt, rt, 0.5f); float newY = Mathf.Lerp(bt, tt, 0.5f); float w = rt - lt; float h = tt - bt; float minx = Mathf.Max(2f, mClipSoftness.x); float miny = Mathf.Max(2f, mClipSoftness.y); if (w < minx) w = minx; if (h < miny) h = miny; // Update the clipping range baseClipRegion = new Vector4(newX, newY, w, h); } static int mUpdateFrame = -1; /// /// Update all panels and draw calls. /// void LateUpdate () { #if UNITY_EDITOR if (mUpdateFrame != Time.frameCount || !Application.isPlaying) #else if (mUpdateFrame != Time.frameCount) #endif { mUpdateFrame = Time.frameCount; // Update each panel in order for (int i = 0, imax = list.Count; i < imax; ++i) list[i].UpdateSelf(); int rq = 3000; // Update all draw calls, making them draw in the right order for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p.renderQueue == RenderQueue.Automatic) { p.startingRenderQueue = rq; p.UpdateDrawCalls(); rq += p.drawCalls.Count; } else if (p.renderQueue == RenderQueue.StartAt) { p.UpdateDrawCalls(); if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count); } else // Explicit { p.UpdateDrawCalls(); if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + 1); } } } } /// /// Update the panel, all of its widgets and draw calls. /// void UpdateSelf () { mUpdateTime = RealTime.time; UpdateTransformMatrix(); UpdateLayers(); UpdateWidgets(); if (mRebuild) { mRebuild = false; FillAllDrawCalls(); } else { for (int i = 0; i < drawCalls.Count; ) { UIDrawCall dc = drawCalls[i]; if (dc.isDirty && !FillDrawCall(dc)) { UIDrawCall.Destroy(dc); drawCalls.RemoveAt(i); continue; } ++i; } } if (mUpdateScroll) { mUpdateScroll = false; UIScrollView sv = GetComponent<UIScrollView>(); if (sv != null) sv.UpdateScrollbars(); } } /// /// Immediately sort all child widgets. /// public void SortWidgets () { mSortWidgets = false; widgets.Sort(UIWidget.PanelCompareFunc); } /// /// Fill the geometry fully, processing all widgets and re-creating all draw calls. /// void FillAllDrawCalls () { for (int i = 0; i < drawCalls.Count; ++i) { if (drawCalls[i] != null) UIDrawCall.Destroy(drawCalls[i]); } drawCalls.Clear(); Material mat = null; Texture tex = null; Shader sdr = null; UIDrawCall dc = null; int count = 0; if (mSortWidgets) SortWidgets(); for (int i = 0; i < widgets.Count; ++i) { UIWidget w = widgets[i]; if (w.isVisible && w.hasVertices) { //Debug.LogError("999999999"); Material mt = w.material; Texture tx = w.mainTexture; Shader sd = w.shader; if (mat != mt || tex != tx || sdr != sd && !w.IsMyWidget)// { if (dc != null && dc.verts.size != 0) { drawCalls.Add(dc); dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; count = 0; dc = null; } mat = mt; tex = tx; sdr = sd; } if (mat != null || sdr != null || tex != null || w.IsMyWidget)//wycm || w.IsMyWidget { if (dc == null || w.IsMyWidget) { if (w.IsMyWidget) { dc = new UIDrawCall(); //UIDrawCall.Create(this, null, null, null, w.gameObject.name, true); drawCalls.Add(dc); } else { dc = UIDrawCall.Create(this, mat, tex, sdr); } dc.depthStart = w.depth; dc.depthEnd = dc.depthStart; dc.panel = this; } else { int rd = w.depth; if (rd < dc.depthStart) dc.depthStart = rd; if (rd > dc.depthEnd) dc.depthEnd = rd; } w.drawCall = dc; ++count; if (w.IsMyWidget) { //dc = UIDrawCall.Create(this, null, null, null, w.gameObject.name, true); //dc = new UIDrawCall(); dc.IsMyWidget = true; //w.drawCall.renderQueue = startingRenderQueue + i; dc.MyWidget = w; //dc.panel = this; //drawCalls.Add(dc); Debug.LogError("IsMyWidget"); //w.drawCall = dc; //w.resetdeth(startingRenderQueue + i); } else { if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans); else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null); if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } } } } else w.drawCall = null; } if (dc != null && dc.verts.size != 0) { drawCalls.Add(dc); dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; } } UIDrawCall.OnRenderCallback mOnRender; /// /// Fill the geometry for the specified draw call. /// bool FillDrawCall (UIDrawCall dc) { if (dc != null) { dc.isDirty = false; int count = 0; for (int i = 0; i < widgets.Count; ) { UIWidget w = widgets[i]; if (w == null) { #if UNITY_EDITOR Debug.LogError("This should never happen"); #endif widgets.RemoveAt(i); continue; } if (w.drawCall == dc) { if (w.isVisible && w.hasVertices) { ++count; if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans); else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null); if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } } else w.drawCall = null; } ++i; } if (dc.verts.size != 0) { dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; return true; } } return false; } /// /// Update all draw calls associated with the panel. /// void UpdateDrawCalls () { Transform trans = cachedTransform; bool isUI = usedForUI; if (clipping != UIDrawCall.Clipping.None) { drawCallClipRange = finalClipRegion; drawCallClipRange.z *= 0.5f; drawCallClipRange.w *= 0.5f; } else drawCallClipRange = Vector4.zero; int w = Screen.width; int h = Screen.height; // Legacy functionality if (drawCallClipRange.z == 0f) drawCallClipRange.z = w * 0.5f; if (drawCallClipRange.w == 0f) drawCallClipRange.w = h * 0.5f; // DirectX 9 half-pixel offset if (halfPixelOffset) { drawCallClipRange.x -= 0.5f; drawCallClipRange.y += 0.5f; } Vector3 pos; if (isUI) { Transform parent = cachedTransform.parent; pos = cachedTransform.localPosition; if (clipping != UIDrawCall.Clipping.None) { pos.x = Mathf.RoundToInt(pos.x); pos.y = Mathf.RoundToInt(pos.y); } if (parent != null) pos = parent.TransformPoint(pos); pos += drawCallOffset; } else pos = trans.position; Quaternion rot = trans.rotation; Vector3 scale = trans.lossyScale; for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; if (dc.IsMyWidget) { dc.renderQueue = startingRenderQueue + i; if (dc.MyWidget != null) dc.MyWidget.resetdeth(startingRenderQueue + i); } else { Transform t = dc.cachedTransform; t.position = pos; t.rotation = rot; t.localScale = scale; dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i; dc.alwaysOnScreen = alwaysOnScreen && (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip); dc.sortingOrder = mSortingOrder; dc.clipTexture = mClipTexture; } } } /// /// Update the widget layers if the panel's layer has changed. /// void UpdateLayers () { // Always move widgets to the panel's layer if (mLayer != cachedGameObject.layer) { mLayer = mGo.layer; for (int i = 0, imax = widgets.Count; i < imax; ++i) { UIWidget w = widgets[i]; if (w && w.parent == this) w.gameObject.layer = mLayer; } ResetAnchors(); for (int i = 0; i < drawCalls.Count; ++i) drawCalls[i].gameObject.layer = mLayer; } } bool mForced = false; /// /// Update all of the widgets belonging to this panel. /// void UpdateWidgets() { #if UNITY_EDITOR bool forceVisible = cullWhileDragging ? false : (Application.isPlaying && mCullTime > mUpdateTime); #else bool forceVisible = cullWhileDragging ? false : (mCullTime > mUpdateTime); #endif bool changed = false; if (mForced != forceVisible) { mForced = forceVisible; mResized = true; } bool clipped = hasCumulativeClipping; // Update all widgets for (int i = 0, imax = widgets.Count; i < imax; ++i) { UIWidget w = widgets[i]; // If the widget is visible, update it if (w.panel == this && w.enabled) { #if UNITY_EDITOR // When an object is dragged from Project view to Scene view, its Z is... // odd, to say the least. Force it if possible. if (!Application.isPlaying) { Transform t = w.cachedTransform; if (t.hideFlags != HideFlags.HideInHierarchy) { t = (t.parent != null && t.parent.hideFlags == HideFlags.HideInHierarchy) ? t.parent : null; } if (t != null) { for (; ; ) { if (t.parent == null) break; if (t.parent.hideFlags == HideFlags.HideInHierarchy) t = t.parent; else break; } if (t != null) { Vector3 pos = t.localPosition; pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); pos.z = 0f; if (Vector3.SqrMagnitude(t.localPosition - pos) > 0.0001f) t.localPosition = pos; } } } #endif int frame = Time.frameCount; // First update the widget's transform if (w.UpdateTransform(frame) || mResized) { // Only proceed to checking the widget's visibility if it actually moved bool vis = forceVisible || (w.CalculateCumulativeAlpha(frame) > 0.001f); w.UpdateVisibility(vis, forceVisible || ((clipped || w.hideIfOffScreen) ? IsVisible(w) : true)); } // Update the widget's geometry if necessary if (w.UpdateGeometry(frame)) { changed = true; if (!mRebuild) { if (w.drawCall != null) { w.drawCall.isDirty = true; } else { // Find an existing draw call, if possible FindDrawCall(w); } } } } } // Inform the changed event listeners if (changed && onGeometryUpdated != null) onGeometryUpdated(); mResized = false; } /// /// Insert the specified widget into one of the existing draw calls if possible. /// If it's not possible, and a new draw call is required, 'null' is returned /// because draw call creation is a delayed operation. /// public UIDrawCall FindDrawCall (UIWidget w) { Material mat = w.material; Texture tex = w.mainTexture; int depth = w.depth; for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; int dcStart = (i == 0) ? int.MinValue : drawCalls[i - 1].depthEnd + 1; int dcEnd = (i + 1 == drawCalls.Count) ? int.MaxValue : drawCalls[i + 1].depthStart - 1; if (dcStart <= depth && dcEnd >= depth) { if (dc.baseMaterial == mat && dc.mainTexture == tex) { if (w.isVisible) { w.drawCall = dc; if (w.hasVertices) dc.isDirty = true; return dc; } } else mRebuild = true; return null; } } mRebuild = true; return null; } /// /// Make the following widget be managed by the panel. /// public void AddWidget (UIWidget w) { mUpdateScroll = true; if (widgets.Count == 0) { widgets.Add(w); } else if (mSortWidgets) { widgets.Add(w); SortWidgets(); } else if (UIWidget.PanelCompareFunc(w, widgets[0]) == -1) { widgets.Insert(0, w); } else { for (int i = widgets.Count; i > 0; ) { if (UIWidget.PanelCompareFunc(w, widgets[--i]) == -1) continue; widgets.Insert(i+1, w); break; } } FindDrawCall(w); } /// /// Remove the widget from its current draw call, invalidating everything as needed. /// public void RemoveWidget (UIWidget w) { if (widgets.Remove(w) && w.drawCall != null) { int depth = w.depth; if (depth == w.drawCall.depthStart || depth == w.drawCall.depthEnd) mRebuild = true; w.drawCall.isDirty = true; w.drawCall = null; } } /// /// Immediately refresh the panel. /// public void Refresh () { mRebuild = true; mUpdateFrame = -1; if (list.Count > 0) list[0].LateUpdate(); } // /// Calculate the offset needed to be constrained within the panel's bounds. /// public virtual Vector3 CalculateConstrainOffset (Vector2 min, Vector2 max) { Vector4 cr = finalClipRegion; float offsetX = cr.z * 0.5f; float offsetY = cr.w * 0.5f; Vector2 minRect = new Vector2(min.x, min.y); Vector2 maxRect = new Vector2(max.x, max.y); Vector2 minArea = new Vector2(cr.x - offsetX, cr.y - offsetY); Vector2 maxArea = new Vector2(cr.x + offsetX, cr.y + offsetY); if (softBorderPadding && clipping == UIDrawCall.Clipping.SoftClip) { minArea.x += mClipSoftness.x; minArea.y += mClipSoftness.y; maxArea.x -= mClipSoftness.x; maxArea.y -= mClipSoftness.y; } return NGUIMath.ConstrainRect(minRect, maxRect, minArea, maxArea); } /// /// Constrain the current target position to be within panel bounds. /// public bool ConstrainTargetToBounds (Transform target, ref Bounds targetBounds, bool immediate) { Vector3 min = targetBounds.min; Vector3 max = targetBounds.max; float ps = 1f; if (mClipping == UIDrawCall.Clipping.None) { UIRoot rt = root; if (rt != null) ps = rt.pixelSizeAdjustment; } if (ps != 1f) { min /= ps; max /= ps; } Vector3 offset = CalculateConstrainOffset(min, max) * ps; if (offset.sqrMagnitude > 0f) { if (immediate) { target.localPosition += offset; targetBounds.center += offset; SpringPosition sp = target.GetComponent<SpringPosition>(); if (sp != null) sp.enabled = false; } else { SpringPosition sp = SpringPosition.Begin(target.gameObject, target.localPosition + offset, 13f); sp.ignoreTimeScale = true; sp.worldSpace = false; } return true; } return false; } /// /// Constrain the specified target to be within the panel's bounds. /// public bool ConstrainTargetToBounds (Transform target, bool immediate) { Bounds bounds = NGUIMath.CalculateRelativeWidgetBounds(cachedTransform, target); return ConstrainTargetToBounds(target, ref bounds, immediate); } /// /// Find the UIPanel responsible for handling the specified transform. /// static public UIPanel Find (Transform trans) { return Find(trans, false, -1); } /// /// Find the UIPanel responsible for handling the specified transform. /// static public UIPanel Find (Transform trans, bool createIfMissing) { return Find(trans, createIfMissing, -1); } /// /// Find the UIPanel responsible for handling the specified transform. /// static public UIPanel Find (Transform trans, bool createIfMissing, int layer) { UIPanel panel = NGUITools.FindInParents<UIPanel>(trans); if (panel != null) return panel; while (trans.parent != null) trans = trans.parent; return createIfMissing ? NGUITools.CreateUI(trans, false, layer) : null; } /// /// Get the size of the game window in pixels. /// public Vector2 GetWindowSize () { UIRoot rt = root; Vector2 size = NGUITools.screenSize; if (rt != null) size *= rt.GetPixelSizeAdjustment(Mathf.RoundToInt(size.y)); return size; } /// /// Panel's size -- which is either the clipping rect, or the screen dimensions. /// public Vector2 GetViewSize () { if (mClipping != UIDrawCall.Clipping.None) return new Vector2(mClipRange.z, mClipRange.w); Vector2 size = NGUITools.screenSize; //UIRoot rt = root; //if (rt != null) size *= rt.pixelSizeAdjustment; return size; } #if UNITY_EDITOR /// /// Draw a visible pink outline for the clipped area. /// void OnDrawGizmos () { if (anchorCamera == null) return; bool clip = (mClipping != UIDrawCall.Clipping.None); Transform t = clip ? transform : mCam.transform; Vector3[] corners = worldCorners; for (int i = 0; i < 4; ++i) corners[i] = t.InverseTransformPoint(corners[i]); Vector3 pos = Vector3.Lerp(corners[0], corners[2], 0.5f); Vector3 size = corners[2] - corners[0]; GameObject go = UnityEditor.Selection.activeGameObject; bool isUsingThisPanel = (go != null) && (NGUITools.FindInParents<UIPanel>(go) == this); bool isSelected = (UnityEditor.Selection.activeGameObject == gameObject); bool detailedView = (isSelected && isUsingThisPanel); bool detailedClipped = detailedView && mClipping == UIDrawCall.Clipping.SoftClip; Gizmos.matrix = t.localToWorldMatrix; #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 if (isUsingThisPanel && !clip && mCam.isOrthoGraphic) #else if (isUsingThisPanel && !clip && mCam.orthographic) #endif { UIRoot rt = root; if (rt != null && rt.scalingStyle != UIRoot.Scaling.Flexible) { float width = rt.manualWidth; float height = rt.manualHeight; float x0 = -0.5f * width; float y0 = -0.5f * height; float x1 = x0 + width; float y1 = y0 + height; corners[0] = new Vector3(x0, y0); corners[1] = new Vector3(x0, y1); corners[2] = new Vector3(x1, y1); corners[3] = new Vector3(x1, y0); Vector3 szPos = Vector3.Lerp(corners[0], corners[2], 0.5f); Vector3 szSize = corners[2] - corners[0]; Gizmos.color = new Color(0f, 0.75f, 1f); Gizmos.DrawWireCube(szPos, szSize); } } Gizmos.color = (isUsingThisPanel && !detailedClipped) ? new Color(1f, 0f, 0.5f) : new Color(0.5f, 0f, 0.5f); Gizmos.DrawWireCube(pos, size); if (detailedView) { if (detailedClipped) { Gizmos.color = new Color(1f, 0f, 0.5f); size.x -= mClipSoftness.x * 2f; size.y -= mClipSoftness.y * 2f; Gizmos.DrawWireCube(pos, size); } } } #endif // UNITY_EDITOR } Assets/NGUI/Scripts/UI/UIPanel.cs(907,44): error CS0619: UnityEngine.RuntimePlatform.WindowsWebPlayer' is obsolete: WebPlayer export is no longer supported in Unity 5.4+.' 这个代码是Unity5.3.3f1版本的,现在升级到Unity 2017.4.0f1 (64-bit)版本

using UnityEngine; using UnityEngine.UI; using System.Collections; [RequireComponent(typeof(CharacterController))] public class _3DPresonMode : MonoBehaviour { [Header("References")] public Camera mainCamera; public GameObject playerModel; public BoxCollider groundCollider; public Button toggleButton; [Header("Settings")] public float moveSpeed = 5f; public float mouseSensitivity = 2f; public float minCameraHeight = 0.5f; public float transitionDuration = 1f; [Header("Rotation Settings")] public bool requireRightClick = true; // 是否需要按住右键旋转 public bool lockCursor = true; // 是否锁定鼠标光标 // 状态变量 private bool isActive = false; private Vector3 initialCameraPosition; private Quaternion initialCameraRotation; private CharacterController characterController; private float rotationX = 0f; private float groundHeight; private Coroutine transitionCoroutine; private Text buttonText; private bool isRotating = false; // 当前是否正在旋转 [Header("Vertical Movement")] public float verticalSpeed = 3f; // 垂直移动速度 public float maxHeight = 25f; // 最大高度限制 public float minHeightOffset = 0.2f; // 最小高度偏移(防止穿透地面) void Start() { // 获取必要组件 characterController = playerModel.GetComponent<CharacterController>(); if (characterController == null) { characterController = playerModel.AddComponent<CharacterController>(); characterController.height = 2f; characterController.radius = 0.5f; characterController.center = Vector3.up; } // 保存初始相机状态 initialCameraPosition = mainCamera.transform.position; initialCameraRotation = mainCamera.transform.rotation; // 计算地面高度 if (groundCollider != null) { groundHeight = groundCollider.bounds.max.y; } else { Debug.LogError("Ground Collider not assigned!"); groundHeight = 0f; } // 设置按钮 if (toggleButton != null) { buttonText = toggleButton.GetComponentInChildren<Text>(); toggleButton.onClick.AddListener(ToggleMode); UpdateButtonText(); } else { Debug.LogError("Toggle button not assigned!"); } // 初始光标状态 UpdateCursorState(); } public void ToggleMode() { isActive = !isActive; if (transitionCoroutine != null) { StopCoroutine(transitionCoroutine); } if (isActive) { transitionCoroutine = StartCoroutine(EnterFirstPersonMode()); } else { transitionCoroutine = StartCoroutine(ExitFirstPersonMode()); } UpdateButtonText(); UpdateCursorState(); } private IEnumerator EnterFirstPersonMode() { // 保存当前相机状态作为过渡起点 Vector3 startPos = mainCamera.transform.position; Quaternion startRot = mainCamera.transform.rotation; // 计算目标位置和旋转 Vector3 targetPos = playerModel.transform.position + Vector3.up * 1.7f; Quaternion targetRot = playerModel.transform.rotation; // 平滑过渡 float elapsed = 0f; while (elapsed < transitionDuration) { float t = elapsed / transitionDuration; mainCamera.transform.position = Vector3.Lerp(startPos, targetPos, t); mainCamera.transform.rotation = Quaternion.Slerp(startRot, targetRot, t); elapsed += Time.deltaTime; yield return null; } // 最终设置 mainCamera.transform.SetParent(playerModel.transform); mainCamera.transform.localPosition = Vector3.up * 1.7f; mainCamera.transform.localRotation = Quaternion.identity; rotationX = 0f; isRotating = false; } private IEnumerator ExitFirstPersonMode() { // 解除相机父子关系 mainCamera.transform.SetParent(null); // 保存当前相机状态作为过渡起点 Vector3 startPos = mainCamera.transform.position; Quaternion startRot = mainCamera.transform.rotation; // 平滑过渡回初始位置 float elapsed = 0f; while (elapsed < transitionDuration) { float t = elapsed / transitionDuration; mainCamera.transform.position = Vector3.Lerp(startPos, initialCameraPosition, t); mainCamera.transform.rotation = Quaternion.Slerp(startRot, initialCameraRotation, t); elapsed += Time.deltaTime; yield return null; } // 最终设置 mainCamera.transform.position = initialCameraPosition; mainCamera.transform.rotation = initialCameraRotation; isRotating = false; } void Update() { if (!isActive) return; HandleMovement(); HandleRotation(); HandleVerticalMovement(); // 添加垂直移动处理 // PreventCameraGroundPenetration(); // 不再需要此方法 } // 新增的垂直移动处理方法 private void HandleVerticalMovement() { float verticalInput = 0f; // 检测按键输入 if (Input.GetKey(KeyCode.Space)) verticalInput = 1f; // 上升 if (Input.GetKey(KeyCode.E)) verticalInput = -1f; // 下降 // 如果没有输入,则不需要移动 if (verticalInput == 0f) return; // 计算目标高度 float targetHeight = playerModel.transform.position.y + verticalInput * verticalSpeed * Time.deltaTime; // 获取地面高度 float currentGroundHeight = GetGroundHeight(); // 应用高度限制 targetHeight = Mathf.Clamp( targetHeight, currentGroundHeight + minHeightOffset, // 最低高度(地面高度 + 偏移) maxHeight // 最高高度 ); // 应用新的高度 Vector3 newPosition = playerModel.transform.position; newPosition.y = targetHeight; playerModel.transform.position = newPosition; } // 获取当前玩家位置下的地面高度 private float GetGroundHeight() { if (groundCollider == null) return 0f; // 创建从玩家位置向下发射的射线 Vector3 rayOrigin = playerModel.transform.position; rayOrigin.y = groundCollider.bounds.max.y + 1f; // 从碰撞器上方开始 // 射线检测 if (Physics.Raycast(rayOrigin, Vector3.down, out RaycastHit hit, Mathf.Infinity)) { // 确保只检测地面碰撞器 if (hit.collider == groundCollider) { return hit.point.y; } } // 如果射线未命中,返回碰撞器顶部高度 return groundCollider.bounds.max.y; } private void HandleMovement() { Vector3 moveDirection = Vector3.zero; if (Input.GetKey(KeyCode.W)) moveDirection += playerModel.transform.forward; if (Input.GetKey(KeyCode.S)) moveDirection -= playerModel.transform.forward; if (Input.GetKey(KeyCode.D)) moveDirection += playerModel.transform.right; if (Input.GetKey(KeyCode.A)) moveDirection -= playerModel.transform.right; if (moveDirection != Vector3.zero) { characterController.SimpleMove(moveDirection.normalized * moveSpeed); } } private void HandleRotation() { // 检查旋转开始条件 if (requireRightClick) { // 右键按下时开始旋转 if (Input.GetMouseButtonDown(1)) { isRotating = true; UpdateCursorState(); } // 右键释放时停止旋转 else if (Input.GetMouseButtonUp(1)) { isRotating = false; UpdateCursorState(); } } else { // 不需要右键,直接激活旋转 isRotating = true; } // 只有旋转激活时才处理输入 if (!isRotating) return; float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity; float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity; // 水平旋转(转动整个玩家模型) playerModel.transform.Rotate(Vector3.up, mouseX); // 垂直旋转(仅旋转相机) rotationX -= mouseY; rotationX = Mathf.Clamp(rotationX, -90f, 90f); // 限制俯仰角 mainCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0); } private void UpdateButtonText() { if (buttonText != null) { buttonText.text = isActive ? "退出" : "巡游"; } } private void UpdateCursorState() { if (!isActive) { // 非第一人称模式:显示光标 Cursor.lockState = CursorLockMode.None; Cursor.visible = true; return; } if (lockCursor) { // 第一人称模式:根据旋转状态设置光标 if (isRotating || !requireRightClick) { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } else { Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } } else { // 不锁定光标 Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } } // 在Inspector中添加调试按钮 [ContextMenu("Fix Rotation")] public void DebugFixRotation() { rotationX = 0f; mainCamera.transform.localRotation = Quaternion.identity; Debug.Log("Camera rotation reset to default"); } } 【出现按键移动错乱的现象,检查代码,修复问题】

/* * Tencent is pleased to support the open source community by making xLua available. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at * http://opensource.org/licenses/MIT * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ using System.Collections.Generic; using System; using UnityEngine; using XLua; //配置的详细介绍请看Doc下《XLua的配置.doc》 public static class ExampleGenConfig { //lua中要使用到C#库的配置,比如C#标准库,或者Unity API,第三方库等。 [LuaCallCSharp] public static List<Type> LuaCallCSharp = new List<Type>() { typeof(System.Object), typeof(UnityEngine.Object), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Quaternion), typeof(Color), typeof(Ray), typeof(Bounds), typeof(Ray2D), typeof(Time), typeof(GameObject), typeof(Component), typeof(Behaviour), typeof(Transform), typeof(Resources), typeof(TextAsset), typeof(Keyframe), typeof(AnimationCurve), typeof(AnimationClip), typeof(Animation), typeof(Animator), typeof(MonoBehaviour), typeof(ParticleSystem), typeof(SkinnedMeshRenderer), typeof(Renderer), typeof(WWW), typeof(System.Collections.Generic.List<int>), typeof(Action<string>), typeof(UnityEngine.Debug), typeof(BoxCollider), typeof(Mathf), typeof(UnityEngine.Random), //typeof(Input), typeof(Screen), typeof(Shader), typeof(Material), typeof(SpriteRenderer), }; //C#静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface [CSharpCallLua] public static List<Type> CSharpCallLua = new List<Type>() { typeof(Action), typeof(Func<double, double, double>), typeof(Action<string>), typeof(Action<double>), typeof(UnityEngine.Events.UnityAction), }; //黑名单 [BlackList] public static List> BlackList = new List>() { new List<string>(){"UnityEngine.WWW", "movie"}, new List<string>(){ "UnityEngine.MonoBehaviour", "runInEditMode"}, new List<string>(){ "UnityEngine.MonoBehaviour", "useGUILayout"}, new List<string>(){"UnityEngine.Texture2D", "alphaIsTransparency"}, new List<string>(){"UnityEngine.Security", "GetChainOfTrustValue"}, new List<string>(){"UnityEngine.CanvasRenderer", "onRequestRebuild"}, new List<string>(){"UnityEngine.Light", "areaSize"}, new List<string>(){"UnityEngine.AnimatorOverrideController", "PerformOverrideClipListCleanup"}, new List<string>(){"UnityEngine.Input", "IsJoystickPreconfigured"}, #if !UNITY_WEBPLAYER new List<string>(){"UnityEngine.Application", "ExternalEval"}, #endif new List<string>(){"UnityEngine.GameObject", "networkView"}, //4.6.2 not support new List<string>(){"UnityEngine.Component", "networkView"}, //4.6.2 not support new List<string>(){"System.IO.FileInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"}, new List<string>(){"System.IO.FileInfo", "SetAccessControl", "System.Security.AccessControl.FileSecurity"}, new List<string>(){"System.IO.DirectoryInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"}, new List<string>(){"System.IO.DirectoryInfo", "SetAccessControl", "System.Security.AccessControl.DirectorySecurity"}, new List<string>(){"System.IO.DirectoryInfo", "CreateSubdirectory", "System.String", "System.Security.AccessControl.DirectorySecurity"}, new List<string>(){"System.IO.DirectoryInfo", "Create", "System.Security.AccessControl.DirectorySecurity"}, }; }

最新推荐

recommend-type

Python打造的Slaee管理系统升级版发布

由于提供的文件信息中,文件名《基于python的slaee管理系统 (15).zip》与描述《基于python的slaee管理系统 (15).zip》相同,并且给出的压缩包文件名称列表中只有一个文件《基于python的slaee管理系统 (14).zip》,该信息表明我们正在讨论两个不同版本的Python系统管理软件的压缩包。以下知识点将根据这些信息详细展开: 知识点一:Python编程语言基础 Python是一种高级编程语言,以其简洁的语法和强大的库支持而闻名。它是解释型语言,具有动态类型系统和垃圾回收功能,适用于多种编程范式,包括面向对象、命令式、函数式和过程式编程。Python广泛应用于系统管理、网络服务器、开发脚本、科学计算、数据挖掘和人工智能等领域。 知识点二:系统管理相关知识 系统管理指的是对计算机系统进行配置、监控和维护的过程,包括硬件资源、软件资源和数据资源的管理。在Python中,系统管理通常涉及操作系统级别的任务,如进程管理、文件系统管理、网络配置、系统日志监控等。Python的系统管理库(例如psutil、fabric、paramiko等)提供了丰富的API来简化这些任务。 知识点三:项目版本控制 从文件名《基于python的slaee管理系统 (14).zip》和《基于python的slaee管理系统 (15).zip》可以看出,这是一个项目在不同版本之间的迭代。版本控制是一种记录一个或多个文件随时间变化的方式,它允许用户可以回到特定版本。在软件开发中,版本控制非常重要,它有助于团队协作、代码合并、分支管理和错误跟踪。常见的版本控制系统包括Git、Subversion (SVN)、Mercurial等。 知识点四:打包与部署 提到“压缩包子文件”,这通常意味着文件已经被压缩打包成一个ZIP文件。在软件开发中,打包是为了便于文件传输、存档保存和分发。在Python项目中,打包也是部署过程的一部分。一个Python项目通常需要包含源代码、依赖关系、配置文件和安装脚本等。打包成ZIP文件后,可以通过各种方式部署到服务器上运行,如使用Fabric或Ansible等自动化部署工具。 知识点五:项目命名及版本命名规则 文件命名中的“基于python的slaee管理系统”表明这是一个与Python语言相关的系统管理项目。而数字“15”和“14”则代表着项目的版本号,这表明项目在持续发展,不同的数字代表了项目在不同时期的迭代。版本号的命名规则通常遵循语义化版本控制(SemVer),这种版本控制系统以 MAJOR.MINOR.PATCH 的形式表示版本号。 知识点六:文件压缩与解压缩技术 ZIP是一种常用的文件压缩格式,它通过减少文件大小来提高存储效率和传输速度。ZIP文件通常是无损压缩,意味着文件在压缩和解压缩的过程中不会丢失信息。Python标准库提供了zipfile模块,允许用户在Python程序中创建ZIP文件、读取ZIP文件内容、提取ZIP文件中的文件等操作。用户可以使用各种图形界面工具(如WinRAR、7-Zip)或命令行工具来处理ZIP文件。 总结以上内容,从文件信息中我们可以得知该内容涉及了Python编程语言、系统管理知识、版本控制、打包与部署、命名规则以及文件压缩技术等多方面的知识点。这些知识点对于理解和应用Python进行系统管理软件开发以及软件的版本迭代、打包与部署均具有重要意义。
recommend-type

深入解析PCB走线传输延时:关键因素与实用公式

# 1. PCB走线传输延时基础 在电子工程领域,尤其是在印刷电路板(PCB)设计中,走线传输延时是一个不可忽视的重要概念。传输延时主要指的是电信号通过PCB上的导电路径从源头传送到目的地所耗费的时间。本章将介绍PCB走线传输延时的基础知识点,为后续章节的深入探讨打下坚实的基础。 首先,了解什么是传输延时是至关重要的。简单来说,它反
recommend-type

gpio很弱是什么意思

<think>嗯,用户的问题是关于GPIO信号弱的概念及其影响。用户似乎对硬件或嵌入式系统有一定了解,但需要更深入的解释。从用户提到的"信号弱"来看,ta可能遇到了实际电路设计中的驱动能力问题,或者在学习GPIO原理时遇到了术语困惑。 用户引用了四篇资料,其中提到GPIO的模拟输入输出模式、施密特触发器的作用、上拉下拉电阻的配置,以及信号线串联电阻的作用。这些内容都与GPIO的驱动能力和信号质量相关。特别是引用[4]中提到的"信号线串联小电阻"和"低频电路不考虑反射",暗示用户可能正在处理实际电路中的信号完整性问题。 用户真正想知道的可能是:为什么我的GPIO输出无法正确驱动某个设备?或者
recommend-type

Python打造的Slaee管理系统升级版发布

标题中的“基于python的slaee管理系统”表明这是一个使用Python编程语言开发的系统。Python是一种广泛使用的高级编程语言,以其易读性和简洁的语法而闻名。SLAEE管理系统可能是指一个特定类型的管理软件,但由于没有给出缩写的完整解释,我们可以假设SLAEE可能是某机构或系统名称的缩写。 从标题和描述来看,存在一处笔误:“基于python的slaee管理系统 (19).zip”和“基于python的slaee管理系统 (18).zip”所指的似乎是同一软件系统,只是版本号不同。根据文件名称列表中的两个文件名,可以推断系统至少有两个版本,一个是版本18,一个是版本19。通常情况下,版本号的增加表示软件进行了更新或改进。 接下来,根据这些信息,我们可以阐述一些相关的知识点: 1. Python编程基础:Python是一种解释型、面向对象、高级编程语言。Python支持多种编程范式,包括过程式、面向对象和函数式编程。Python由于其简洁和易于学习的特性,被广泛应用于网络开发、数据分析、人工智能、机器学习和科学计算等领域。 2. 文件压缩与打包:文件压缩是将文件的大小减小以节省存储空间或网络传输时间的技术。常见的文件压缩格式包括ZIP、RAR、7Z等。文件打包通常指的是将多个文件或文件夹压缩成一个单独的文件。这在数据备份、软件分发和档案管理中非常常见。 3. 版本控制:在软件开发中,“版本”通常指软件的特定状态,版本号则用来标识这些状态。版本控制是一种记录文件、目录或集合随着时间变化的方式,以便将来可以检索特定版本。对于软件项目来说,版本控制是至关重要的,它不仅允许开发者追踪和管理代码的变化,而且还能帮助团队协作,解决冲突,并回滚到旧版本。 4. 软件管理系统的开发:一个软件管理系统可能是针对特定业务领域而设计的,它可能包括用户界面、数据库管理、业务逻辑处理、报告生成和其他许多功能。软件管理系统的开发通常涉及需求分析、系统设计、编程、测试和维护等多个阶段。 5. Python在软件开发中的应用:Python因为具有丰富的库和框架,被广泛用于开发各种类型的软件。例如,Django和Flask是用于Web开发的流行Python框架;而对于数据分析和数据科学任务,Pandas、NumPy和Matplotlib等库提供了强大的数据处理和可视化工具;对于机器学习和人工智能,TensorFlow、PyTorch等库使得复杂算法的实现变得更为简单。 6. 系统更新与维护:随着软件的使用和发展,需求可能会变化,新的问题可能会出现,所以软件系统需要定期进行更新和维护。软件更新可能包括修复已知问题、改进现有功能、增加新功能或优化性能。开发者需要评估是否需要为修复安全漏洞或提高系统性能而更新系统,以及更新之后对用户体验的影响。 由于文件名中只提到了“基于python的slaee管理系统”,没有提供该系统具体功能的详细描述,我们无法提供更加具体的技术知识点。如果需要分析系统的工作原理或具体的技术实现细节,还需要更多的信息。
recommend-type

【Keil-ARM编程艺术】:如何编写可维护且高效的代码

# 摘要 本文旨在为读者提供ARM微控制器编程和Keil开发环境的全面指南。第一章概览了ARM微控制
recommend-type

应用层协议概述

<think>首先,用户的问题是:“我想了解应用层协议的基本概念和常见类型 请问应用层协议简介 常见应用层协议概述”。这翻译成:“I want to understand the basic concepts of application layer protocols and common types. Please introduce application layer protocols and overview common application layer protocols.” 根据系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$格式
recommend-type

Delphi 12 TeeChartVCLFMX控件包下载及功能介绍

标题中提到的"Delphi 12 控件之TeeChartVCLFMX-2024.40.rar"指的是Delphi 12版本中使用的TeeChartVCLFMX图表控件的特定版本(2024.40版本)。Delphi是由Embarcadero Technologies开发的一款流行的集成开发环境(IDE),专门用于使用Object Pascal和C++语言开发软件应用程序。该标题强调了Delphi 12环境下TeeChartVCLFMX控件的使用,这表明Delphi的图形用户界面(GUI)组件库中包含了一个专门用于创建复杂图表和图形的组件。 从描述中仅能得到的关于文件的名称是"TeeChartVCLFMX-2024.40.rar",这意味着文件是一个压缩包,具体包含了一个TeeChartVCLFMX的图表控件,版本号为2024.40。它可能包含了在Delphi 12版本中使用该图表控件所需的所有文件,包括库文件、二进制文件、文档等。 标签"delphi 控件"简单而直接地指出了该文件属于Delphi编程环境中的一个控件类别,表明了目标用户是Delphi开发者,他们通常使用这些控件来丰富他们的应用程序界面或增强应用程序的功能。 文件名称列表提供了关于TeeChartVCLFMX压缩包内包含的具体文件及其用途的详细信息: 1. TeeChartVCLFMX-2024.40.exe:这个文件很可能是一个安装程序或可执行文件,用于安装或运行TeeChartVCLFMX图表控件。 2. Keygen.exe:这个文件名表明它可能是一个密钥生成器(Key Generator),用于生成软件的注册码或激活码,使得控件可以脱离试用限制或进行合法授权。 3. Delphi29Binaries-2024.40-windows.pak:这个文件名暗示它包含了特定于Windows平台的Delphi 29(可能指的是Delphi 12的内部版本号)的二进制文件。pak文件是压缩包的一种格式,可能包含了运行TeeChartVCLFMX图表控件所需的库文件、DLLs、组件文件等。 4. TeeChartVCLFMX-2024.40 - D12.pdf:这是一个PDF格式的文件,很可能是用户手册或帮助文档,提供了对TeeChartVCLFMX图表控件版本2024.40在Delphi 12中的使用说明,安装指南,功能介绍或示例代码等。 综合以上信息,可以推断TeeChartVCLFMX-2024.40压缩包是为Delphi 12的开发人员提供了一个专业的图表解决方案,使得用户能够将图表功能集成到他们用Delphi开发的应用程序中。TeeChartVCLFMX可能包含各种图表类型(如条形图、折线图、饼图等),以及丰富的定制选项,如颜色、样式、图例、数据绑定、交互式功能等。开发者可以利用TeeChartVCLFMX提供的图表控件在应用程序中创建强大的数据可视化功能,这对数据分析、科学计算、商业智能、财务报告等领域特别有用。 开发者需要使用Delphi 12 IDE配合提供的组件安装程序或执行文件安装和配置TeeChartVCLFMX控件,通过阅读PDF文档来了解如何使用控件,并在需要时使用Keygen.exe激活控件。Delphi29Binaries-2024.40-windows.pak文件可能包含了控件运行所需的核心二进制组件。通过合理使用这些资源,开发者可以将TeeChartVCLFMX控件集成到自己的项目中,快速构建功能丰富的图表和数据可视化组件。
recommend-type

【Keil-ARM性能优化全解】:代码监控与优化工具的实用技巧

# 摘要 本文对基于Keil-ARM平台的性能优化进行了系统性探讨,涵盖了性能监控工具的介绍、代码优化策略、系统资源管理以及综合案例分析。首先,介绍了Keil-ARM的性能监控工具及其在性能分析中的重要性,包括工具的配置和性能数据解读方法。其次,文中讨论了代码层面的优化,包括高效循环和条件语句的编写,函数内联与尾调用优化,以及编译器优化选项的应用。然后,深入分析了ARM系统资源分配、
recommend-type

电子邮箱协议

<think>首先,用户的问题是:“我想了解电子邮箱相关的协议 请问电子邮件协议有哪些”。这直接询问电子邮件协议的种类。 从系统级指令中,我需要: - 使用中文回答。 - 结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 - 在行内数学表达式使用 $...$,但这里可能没有数学内容。 - 独立公式使用 $$...$$,但可能不需要。 - 生成相关问题。 - 在引用的段落末尾添加引用标识如 [^1]。 参考提供的引用: - 引用[1]: 讨论了SMTP、POP3和IMAP。 - 引用[2]: 提到电子邮件系统采用客户机/服务器模式,涉及接收和发送邮件。 - 引用[3]: 详细描述了P
recommend-type

深入理解Docker在目标检测中的应用

根据给定文件信息,我们首先需要明确这是一个有关Docker的笔记文档。Docker是一种流行的开源容器化平台,用于自动化部署、扩展和管理应用程序。在本篇内容中,我们将围绕Docker技术进行详细讲解,涵盖其核心概念、工作原理以及如何应用于实际项目中,尤其是涉及到对象检测(object detection)这一人工智能领域的子集。 ### Docker核心概念与工作原理 1. **容器(Container)**: Docker容器是一个轻量级、独立的可执行包,包含了运行所需的一切:代码、运行时、系统工具、系统库和设置。与传统的虚拟机相比,容器不包含一个独立的操作系统,而是共享宿主机的操作系统内核,这使得容器更加轻量和高效。 2. **镜像(Image)**: Docker镜像是构建容器的模板。镜像可以基于其他镜像进行修改,并可以保存这些更改,从而创建新的镜像。镜像是一种不可变的文件,是容器运行的静态形式。 3. **Dockerfile**: Dockerfile是一个文本文件,包含了创建Docker镜像的指令。通过Dockerfile,开发者可以定义一个脚本化的构建流程,使得构建镜像的过程变得可复现和自动化。 4. **Docker守护进程(Docker daemon)**: Docker守护进程是一个运行在宿主机上的后台进程,负责构建、运行和分发容器。用户通过与守护进程通信来控制或管理容器。 5. **仓库(Repository)**: Docker仓库用来存放镜像,并提供了镜像的共享和分发服务。仓库分为公开(public)和私有(private)两类。 6. **Docker Compose**: Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过Compose,使用YAML文件来配置应用程序的服务。然后,使用一个命令,就可以创建并启动所有服务。 ### Docker在对象检测中的应用 在人工智能领域,尤其是在计算机视觉和深度学习领域,对象检测是一个识别图像中各种对象及其位置的技术。Docker在其中的应用主要体现在以下几个方面: 1. **环境隔离**: 每个容器都运行在隔离的环境中,这意味着不同的机器学习模型和开发环境可以在同一台主机上共存而不产生冲突。这对于依赖不同Python版本、库或框架的机器学习项目特别有用。 2. **版本控制**: 使用Docker镜像可以捕获特定版本的运行环境,包括操作系统的依赖库和框架版本。这样可以确保在不同环境(开发、测试和生产环境)中运行相同版本的应用程序。 3. **便于分发与部署**: 将训练好的模型封装在Docker容器中,可以通过Docker镜像轻松地部署到不同的机器或云平台,而无需担心环境配置问题。 4. **扩展性与灵活性**: Docker容器的轻量级特性使得按需扩展应用变得简单高效。在需要处理大量并发任务的对象检测系统中,可以快速启动多个容器实例,应对负载。 5. **持续集成与持续部署(CI/CD)**: Docker与CI/CD工具的结合可以使得对象检测应用的持续集成和部署流程自动化,从而加快开发周期,确保软件质量和快速迭代。 ### 实际操作与技术细节 在`object-detection-main`这个Docker相关项目中,可以假设我们正在处理一个使用深度学习进行对象检测的机器学习项目。可能的步骤包括: 1. **环境配置**: 创建一个`Dockerfile`,指定基础镜像(例如`python:3.7`),安装所有必要的依赖,如`tensorflow`、`keras`、`opencv-python`等。 2. **代码迁移**: 将训练好的模型文件和相关代码复制到容器的适当位置。 3. **服务定义**: 使用`docker-compose.yml`定义多个容器服务,比如前端服务、API服务、数据库服务等。 4. **构建与运行**: 运行`docker build`命令来构建镜像,然后使用`docker-compose up`来启动服务。 5. **测试与优化**: 进行必要的测试来确保对象检测模型在容器中正常运行,并根据性能指标进行优化调整。 6. **部署与监控**: 将构建好的容器镜像部署到服务器或云平台,同时设置监控以确保系统的稳定性和效率。 7. **持续反馈与改进**: 根据用户反馈和监控结果,持续改进模型的准确性和系统性能。 通过以上的步骤和技术细节,可以对Docker在对象检测项目中的应用有一个整体的把握。Docker技术的应用使得模型的部署和运维变得更加简单和高效,特别是在当今微服务架构和容器化技术盛行的大环境下。